I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?
That's why Rust's Result is vastly superior because it out of box pushes the users to very efficient and idiomatic error handling mechanism which is based on its enum types that enjoy a lot of compiler optimizations.
You can also achieve fairly good results with struct-based custom Result implementations in C# but until the language gets the support of proper discriminated unions, it will always be inferior.
Thankfully, in C# and, I assume, in other exception-based languages the compiler is smart enough to recognize exceptions as cold paths and correctly reorder emitted code to minimize their impact when you do not throw them. But traversing try-catch blocks still tends to pessimize the codegen significantly hence heavy reliance of C# on various throw helpers to keep hot paths clean.