While looking into a Bug that had to do with erroneous handling of Exceptions I came across an interesting C# ‘feature’ that can cause unintended information loss with Exceptions.
Have a look at the following typical code example from OpenPetra:
catch (Exception e)
{
TLogging.Log(e.GetType().ToString() + " in BankImport, GetBankStatementTransactionsAndMatches; " + e.Message);
TLogging.Log(e.StackTrace);
DBAccess.GDBAccessObj.RollbackTransaction();
throw e;
}
Here, the callstack up till the Execption Handler gets thrown away, hence we are loosing valuable debugging information upstream. True, in this case the stacktrace gets logged first, but this isn’t always the case in such constructs, and even if so, the callstack isn’t available upstream anymore for inspection or logging (e.g. on the Client side if the code that re-raises the Exception is server-side).
Reason for that (somewhat unexpected) behaviour:
The callstack is thrown away if a 'throw' statement is used in conjunction with the Exception variable, e.g. 'throw e;'. The callstack is not lost if the throw statement is used on its own: 'throw;'. Doing it the latter way is therefore recommended and has the same effect of re-raising the Exception (the one that the catch block is dealing with) than the variant with the Exception variable - only the callstack is preserved in this case!
Reference: Last code example and explanation on this web page: http://msdn.microsoft.com/en-us/library/ms229005
We should therefore strive to use ‘throw;’ on its own (unless we are not re-throwing but throwing a different Exception altogether [with ‘throw new xxx;’]).
I have corrected all places in our whole C# source code where the callstack was thrown away so that it doesn’t happen anymore (in the following commit: http://bazaar.launchpad.net/openpetracore/openpetraorg/trunkhosted/revision/1780).
Kind regards,
christiank