Sunday, March 12, 2006 9:46 PM bart

To throw or to rethrow?

It has been a long time since my last technical post on my blog over here. Let's do something about it. A couple of days ago I was made aware of some strange behavior on the field of exception handling in the .NET Framework. Although a little surprised in the beginning, I took the tools in hand and started to investigate the following behavior.

What will be the output of the following?

using System;

class Ex
{
   public static void Main()
   {
      //
      // First test rethrowing the caught exception variable.
      //
      Console.WriteLine("First test");
      try
      {
         ThrowWithVariable();
      }
      catch (Exception ex)
      {
         Console.WriteLine(ex.StackTrace);
      }

      //
      // Second test performing a blind rethrow.
      //
      Console.WriteLine("Second test");
      try
      {
         ThrowWithoutVariable();
      }
      catch (Exception ex)
      {
         Console.WriteLine(ex.StackTrace);
      }
   }

   private static void BadGuy()
   {
      //
      // Some nasty behavior.
      //
      throw new Exception();
   }

   private static void ThrowWithVariable()
   {
      try
      {
         BadGuy();
      }
      catch (Exception ex)
      {
         throw ex;
      }
   }

   private static void ThrowWithoutVariable()
   {
      try
      {
         BadGuy();
      }
      catch
      {
         throw;
      }
   }
}

This piece of code uses "exception rethrow" in two different ways. The first test rethrows the exception object received through the catch block parameter, whileas the second one performs kind of a blind rethrow just using the keyword "throw". I'm not going to cover the scenarios where rethrowing an exception is a good design choice over here (e.g. from a performance point of view you should try to avoid rethrowing exceptions). Nevertheless, the behavior is different in both cases. Here's the output:

First test
   at Ex.ThrowWithVariable()
   at Ex.Main()
Second test
   at Ex.BadGuy()
   at Ex.ThrowWithoutVariable()
   at Ex.Main()

Oops, our bad guy has disappeared in the first test, but why?

 

Sniffing a line of IL

Time for ildasm.exe once again. Regular blog readers will know ildasm.exe is still one of my favorite tools (with reason in my opinion). Here's the code for the ThrowWithVariable method:

.method private hidebysig static void  ThrowWithVariable() cil managed
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (class [mscorlib]System.Exception V_0)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  call       void Ex::BadGuy()
    IL_0007:  nop
    IL_0008:  nop
    IL_0009:  leave.s    IL_000f
  }  // end .try
  catch [mscorlib]System.Exception
  {
    IL_000b:  stloc.0
    IL_000c:  nop
    IL_000d:  ldloc.0
    IL_000e:  throw
  }  // end handler
  IL_000f:  nop
  IL_0010:  ret
} // end of method Ex::ThrowWithVariable

Ignore the nop statements due to the debugging build. As you can see, the exception being thrown over here is grabbed from the locals (V_0). However, the second test contains different code:

.method private hidebysig static void  ThrowWithoutVariable() cil managed
{
  // Code size       17 (0x11)
  .maxstack  1
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  call       void Ex::BadGuy()
    IL_0007:  nop
    IL_0008:  nop
    IL_0009:  leave.s    IL_000f
  }  // end .try
  catch [mscorlib]System.Object
  {
    IL_000b:  pop
    IL_000c:  nop
    IL_000d:  rethrow
  }  // end handler
  IL_000f:  nop
  IL_0010:  ret
} // end of method Ex::ThrowWithoutVariable

Over here, the caught exception s grabbed from the stack and rethrown directly. Because of this, we keep the existing information of the original exception and reuse it. To understand the overall behavior of the exception handler and the relation to the stack, it's sufficient to understand that the exception object is living on top of the stack when entering the catch block. Also notice that our "catch all" was translated to a catch block handling objects of the type System.Object (no, System.Exception should not be the parent of all exception types in .NET, that's just a rule which is enforced by the compilers).

 

Conclusion

A "blind" rethrow is the best way to rethrow an exception because it maintains all the information about the real origin of the exception. Don't get caught by this behavior :-).

UPDATE: Robert (see comments) points out that a blind rethrow isn't a good idea. I agree on this point, but this conclusion is not dealing with the "philosophy of exception handling". Instead, this conclusion is only based on the comparison between "throw" and "throw ex". Whether doing such a thing without wrapping the exception and adding additional information is a good idea, isn't the scope of this post. Check out Brad Adams' PPT on this subject for more information.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: ,

Comments

# re: To throw or to rethrow?

Monday, March 13, 2006 10:38 PM by Robert Bogue

I disagree with some of your statements ...

1) Rethowing an exception is bad -- it should be done when data can be added to help identify the cause of the exception. If exceptions are truly exceptions then the performance impact is negligible. (Since they shouldn't be happening often enough to matter.)

2) You should blind rethrow. (See #1.) You should wrap the exception with more data and throw it up.

I've got an article on the approach at Developer.com called "Handling Exceptions". It's available at http://www.developer.com/tech/article.php/3370341

Rob

# CLR exception handling from A to Z - Everything you didn't want to know about try-catch-finally-fault-filter

Tuesday, April 04, 2006 2:11 AM by B# .NET Blog

What is it?
The principle of exceptions is a pretty
easy-to-understand way to report exceptional situations...

# CLR exception handling from A to Z - Everything you didn't want to know about try-catch-finally-fault-filter

Tuesday, April 04, 2006 2:11 AM by B# .NET Blog

What is it?
The principle of exceptions is a pretty
easy-to-understand way to report exceptional situations...

# re: To throw or to rethrow?

Wednesday, April 12, 2006 9:01 PM by bart

Robert, in this post I don't have the intention to debate about whether you have to rethrow exceptions or not and in which scenarios this is a good idea. The only thing I want to point out is that there's a difference between "throw" and "throw ex" in C#. It's up to the reader to decide where this might be useful. For instance, Visual Basic has exception filters but C# doesn't. So you might have to catch an exception, investigate whether you can deal with it, and if not decide to rethrow it blindly to maintain the origin of the exception. However, at the border of some module this might not be a good idea since wrapping the exception in a custom exception type using InnerException to create a chain of exceptions is a far better option. Again, this discussion is not the intention of this post. The only intention I had was to point out the differences between "throw" and "throw ex" in C#, which maps to "rethrow" and "throw" in IL. That - and nothing more - was the topic of this post.

# CLR exception handling from A to Z - Everything you didn't want to know about try-catch-finally-fault-filter

Sunday, January 06, 2008 6:06 PM by B# .NET Blog

What is it? The principle of exceptions is a pretty easy-to-understand way to report exceptional situations

# GMBSG - Stories » Die alte Geschichte: throw; vs. throw e;

Pingback from  GMBSG - Stories  » Die alte Geschichte: throw; vs. throw e;

# Tips for programmer

Tuesday, March 06, 2012 10:12 PM by Tips for programmer

Pingback from  Tips for programmer

# Tips for programmer

Tuesday, March 06, 2012 10:12 PM by Tips for programmer

Pingback from  Tips for programmer

# ???VS?????????????????????????????????Throw VS rethrow : same result? | BlueFAQ | C#

Pingback from  ???VS?????????????????????????????????Throw VS rethrow : same result?  | BlueFAQ | C#