This is the second part of the .NET Inside Out series. For your convenience you can find other parts in the table of contents in Part 1 – Virtual and non-virtual calls in C#

Today we are going to dive into exceptions in .NET world. Handling them right might be a bit tricky, especially when you do not understand internals.

Exceptions at a glance

I assume you know what is an exception, when it should be used, how to throw it, and how to catch it. You can also read about exception internals

Rethrowing exceptions

We know how to throw and catch exception. Imagine now, that we want to catch exception, examine it and do something (e.g., log its message), and then rethrow it. Let’s take the following code:

We have method named MethodThrowingException which throws exception of type ArgumentException. Next, we have method MethodRethrowingException which calls MethodThrowingException twice, handles exception and rethrows it. Finally, in Main we first set culture to English (in order to have readable exception descriptions), and next we call method handling exceptions.

Two things are worth noting here: we call method MethodThrowingException twice (even though it always throws exception and second invocation never happens). We also check the message of the exception when handling it, but it never meets condition so we always rethrow it without doing anything.

Since Main does not handle exceptions, they will be printed out to the console (with all inner exceptions), and the program will crash. Let’s now examine three methods of rethrowing exception.

Rethrowing by throwing the same exception again

We can use the following line:

It throws existing exception. Let’s see it in action, this is the program output:

So what did we get here? Our stacktrace contains only information related to last throw. We lost all informations about the exception being thrown in the first place.

Never rethrow exception this way!

Let’s now see the stacktrace visible by the debugger:

We can’t see original frame of the method which was first to throw.

Rethrowing by throw;

Most of the C# books says that the right way to rethrow exception is the instruction throw;. Let’s see it in action:

Indeed, this time we have line which originally thrown the exception. Let’s see WinDBG stacktrace:

Unfortunately, stacktrace didn’t change. We still can’t see the datils. But we have them in our exception object, so we can extract them anyway, can’t we?

Well, the answer is: not really. Are you able to tell which invocation of MethodThrowingException thrown exception? Remember that we are calling this method twice but there is no clue in stacktrace or exception which invocation was the one to blame. We could try to analyze the code but we have no stack parameters anymore, so it is not always sufficient.

Most books describe throw; as a proper way to rethrow exception. But it is not enough!

So how should we rethrow exception?

Create new exception and throw it

Let’s now rethrow the exception with the following line:

Output:

This time we finally have all informations. Let’s see the WinDBG stacktrace:

Unfortunately, stacktrace is still the same.

But! This changes the type of the exception which can change the logc of your code badly. SO you should not do it just like that, you should probably use reflection to create exception of the same type (which might no be possible though).

PrepForRemoting

Milosz Krajewski suggested yet another way. There is an internal method PrepForRemoting which sets the field _remoteStackTraceString. If you call it the stacktrace is preserved:

Output:

ExceptionDispatchInfo

.NET 4.5 introduced class ExceptionDispatchInfo which can capture exception and rethrow it somewhere else without spoiling the stack trace. Let’s see it in action:

Output:

And now WinDBG callstack:

It looks like nothing changed.

So what is the right way to rethrow exception? It looks like PrepForRemoting is the best. It works on old .NET Framework and contains most of useful data. If in .NET 4.5, just use new method.

Examining exception

Our exception handler does something interesting only when the message is set to correct value. Most of the times this is not the case so it does nothing. Is there a better approach to perform this message check?

C# 6 introduced filtering statement for exception handlers. Let’s see them in action:

So we moved our condition to special filter outside of the exception handler. Does it change anything? If you run this application with different rethrowing instructions, the output will be different:

There is no surprise here: since our exception handler didn’t execute, we didn’t need to rethrow exception, so we get original stacktrace regardless the rethrowing method. Let’s now see the WinDBG:

This is very important. New syntax allows us to not execute the exception handler when the condition is not met. When it is the case, the stacktrace does not change!

Conclusion

Most of C# books describes throw; instruction as the way to go. However, be very careful with it since it loses some pieces of information. It might look like not interesting edge case (why do you want to call particular function multiple times?), but you should be aware of this behaviour. Also, always try to use new syntax for filtering exceptions since it doesn’t modify call stack. One day it might save your life.