The Mistake Every C# Programmer Makes

In the C# projects I have worked in over the last 5 years or so, I see the same mistake being made constantly, often with irritating results when it comes to traking down problems in production systems. The cause of the problem is that most C# programmers I have met doesn't know the difference between throwing an exception, and rethrowing an exception. When an exception is thrown, the frames in the call stack are recorded the Exception.StackTrace property. This provides vital information in tracking down the root problem that caused the exception. The StackTrace property is reset every time an exception object is thrown:

try{
//code here
}
catch(Exception ex){
//some code here related to the exception 
throw ex; //Reset the StackTrace to make finding the real problem harder to find
}


When the exception bubbles up to a point where it is handled via detailed logging or caught in a debugger, the StackTrace will only contain information on the stack frames up to the point where the exception is caught and then thrown again. If the exception is not logged sufficiently at each point where it is caught, it can make tracking down the root problem impossible without attaching a debugger. It is also poor practice.
There are two solutions to the problem dont catch the Exception unless you can do something meaningful with it, or, if catching if required, rethrow the same exception. The C# syntax for rethrowing an exception is the throw keyword without an expression. The C# language specification (v1.2) states: A throw statement with no expression can be used only in a catch block, in which case that statement re-throws the exception that is currently being handled by that catch block.
The code presented above can be fixed by removing the expression after the throw statement:

try{
//code here
}
catch(Exception ex){
//some code here related to the exception
throw; //Notice the absence of the ex expression
}


At a MSIL level, a different instruction is used in the two cases. The catch block in the first code same will compile to:

catch [mscorlib]System.Exception   
{
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: throw  
} // end handler


In contrast, the catch block on second code sample will compile to:

catch [mscorlib]System.Exception   
{
IL_000c: stloc.0
IL_000d: rethrow  
} // end handler


It is unfortunate that the C# language syntax is less clear and obvious than the MSIL.
An added benefit of not re-setting the stack trace is that the code will run faster, as the unnecessary stack capture is avoided.
Posted: Jul 04 2006, 05:06 AM by nick | with 4 comment(s)
Filed under:

Comments

Nick Randolph said:

Great post! For those working in VB.NET the same applies. DON'T call "throw ex" unless you want to reinitialise the StackTrace.
# July 4, 2006 3:00 AM

El Bruno said:

Nice information ... I'll check my code searching for some "throw ex" code !!!

Bye from Spain.
# July 4, 2006 6:25 AM

Mitch Wheat said:

Hi Nick

How's the photography going?

Nice post. I'me sure there's quite a few people out there that do not appreciate the difference. I've seen and caught (excuse pun!) this problem at a few places I've been consulting in the last 2 years. It's been part of my C# coding standards and guidelines for a while.

Regards,
Mitch Wheat
# July 4, 2006 9:21 AM

David M. Kean said:

If you are running FxCop, RethrowToPreserveStackDetails will fire on 'throw ex'.
# July 4, 2006 9:35 AM