Coder Perfect

Catching and rethrowing.NET exceptions: best practices

Problem

What are the best practices to follow when catching and rethrowing exceptions? I want to make sure that the InnerException and stack trace of the Exception object are preserved. Is there a difference in the way the following code blocks deal with this?

try
{
    //some code
}
catch (Exception ex)
{
    throw ex;
}

Vs:

try
{
    //some code
}
catch
{
    throw;
}

Asked by Seibar

Solution #1

The way to preserve the stack trace is through the use of the throw; This is valid as well

try {
  // something that bombs here
} catch (Exception ex)
{
    throw;
}

Because throw ex; is essentially the same as throwing an exception from that point on, the stack trace will only go to the point where the throw ex; statement is sent.

Mike is also correct, providing you can pass an exception with the exception (which is recommended).

In his foundations of programming e-book, Karl Seguin has an excellent write-up on exception management that is definitely worth reading.

Edit: The link to the Foundations of Programming pdf is now active. Simply look for the word “exception” in the text.

Answered by Darren Kopp

Solution #2

If you throw a new exception with the original exception, the stack trace will be preserved as well.

try{
} 
catch(Exception ex){
     throw new MoreDescriptiveException("here is what was happening", ex);
}

Answered by Mike

Solution #3

In fact, the toss statement will not save the StackTrace information in some circumstances. For instance, consider the following code:

try
{
  int i = 0;
  int j = 12 / i; // Line 47
  int k = j + 1;
}
catch
{
  // do something
  // ...
  throw; // Line 54
}

Although the exception was raised at line 47, the StackTrace will show that it was raised at line 54.

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.WithThrowIncomplete() in Program.cs:line 54
   at Program.Main(String[] args) in Program.cs:line 106

There are two ways to restore the original StackTrace in circumstances like the one mentioned above:

Calling the Exception.InternalPreserveStackTrace

Because it is a private method, it must be called via reflection:

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

The fact that I rely on a private function to save the StackTrace information is a drawback. It can be altered in future.NET Framework releases. Fabrice MARGUERIE’s blog provided the code example above and the proposed solution below.

Calling Exception.SetObjectData

Anton Tykhyy provided the solution below in response to the question “In C#, how can I rethrow InnerException without loosing stack trace?”

static void PreserveStackTrace (Exception e) 
{ 
  var ctx = new StreamingContext  (StreamingContextStates.CrossAppDomain) ; 
  var mgr = new ObjectManager     (null, ctx) ; 
  var si  = new SerializationInfo (e.GetType (), new FormatterConverter ()) ; 

  e.GetObjectData    (si, ctx)  ; 
  mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData 
  mgr.DoFixups       ()         ; // ObjectManager calls SetObjectData 

  // voila, e is unmodified save for _remoteStackTraceString 
} 

Although it has the advantage of relying solely on public methods, it also relies on the exception constructor below (which some exceptions developed by 3rd parties do not implement)

protected Exception(
    SerializationInfo info,
    StreamingContext context
)

Because the exceptions thrown by a 3rd-party package I was using didn’t implement this constructor, I had no choice but to take the first solution in my circumstance.

Answered by CARLOS LOTH

Solution #4

When you toss ex, you’re essentially throwing a new exception, therefore the original stack trace information will be lost. The throw method is the most popular.

Answered by Forgotten Semicolon

Solution #5

The basic Exception object should not be caught or thrown, as a rule of thumb. This causes you to think about exceptions a little more carefully; for example, you should include an explicit catch for a SqlException so that your handling code doesn’t make a mistake with a NullReferenceException.

In the real world, though, catching and reporting the base exception is a fine practice, but don’t forget to walk the entire thing to obtain any InnerExceptions it may have.

Answered by swilliams

Post is based on https://stackoverflow.com/questions/22623/best-practices-for-catching-and-re-throwing-net-exceptions