Click here to Skip to main content
15,869,940 members
Articles / General Programming / Exceptions

Exception Handling Particulars in C#

Rate me:
Please Sign up or sign in to vote.
4.87/5 (19 votes)
28 Jul 2011CPOL3 min read 43.4K   19   16
Describes low level differences between several Exception handling grammar including: throw and throw ex; catch and catch (Exception ex)

Background

Exception handling appears in most .NET applications, this post is trying to describe some Exception handling particulars in C# which might not take enough awareness from C# developers.

Differences Between throw and throw ex

I guess every C# developer has seen the code snippet below:

C#
try
{
   // Do some work, exception occurs
}
catch (IOException ex)
{
   // Exception caught, re-throw it to bubble up
   throw ex;
}

In the catch block, we can rethrow the caught exception instance of IOException to a higher level, and we may also see another way in a slightly different manner:

C#
try
{
   // Do some work, exception occurs
}
catch (IOException ex)
{
   // Exception caught, re-throw it to bubble up
   throw;
}

Is there any difference? The answer is yes! To prove that, I wrote a simple snippet of code below, first is a simple customized Exception: DummyException.

C#
internal class DummyException : Exception
{
   public DummyException(String dummymsg)
     : base(dummymsg)
   {

   }

   public DummyException(String dummymsg, Exception innerException)
     : base(dummymsg, innerException)
   {

   }
}

And then I manually throw the DummyException within one method, while handling it in a different way mentioned above:

C#
class Program
{
   private static void DoLowLevelOperation()
   {
     // Do some low level operation
     throw new DummyException("A dummy exception message!");
   }

   public static void MethodThrowException1()
   {
     try
     {
       DoLowLevelOperation();
     }
     catch (DummyException de)
     {
       throw;
     }
   }
   public static void MethodThrowException2()
   {
     try
     {
       DoLowLevelOperation();
     }
     catch (DummyException de)
     {
       throw de;
     }
   }

   static void Main(string[] args)
   {
     try
     {
       MethodThrowException1();
     }
     catch (DummyException de1)
     {
       Console.WriteLine(de1.Message);
       Console.WriteLine(de1.StackTrace);
     }

     try
     {
       MethodThrowException2();
     }
     catch (DummyException de2)
     {
       Console.WriteLine(de2.Message);
       Console.WriteLine(de2.StackTrace);
     }
   }
}

The result will be:

228868/EXHandling.png

So the difference is, "throw ex" will truncate the StackTrace information where it was originally thrown (this will cause the so called issue - "breaking the stack"), but "throw" will contain all the information.

Delve deeper, "throw ex" in IL level essentially indicates "rethrow", whereas "throw" indicate "throw", please see their IL code below:

MSIL
.method public hidebysig static void MethodThrowException1() cil managed
{
   .maxstack 1
   .locals init (
     [0] class ConsoleUnitTest.DummyException de)
   L_0000: nop
   L_0001: nop
   L_0002: call void ConsoleUnitTest.Program::DoLowLevelOperation()
   L_0007: nop
   L_0008: nop
   L_0009: leave.s L_000f
   L_000b: stloc.0
   L_000c: nop
   L_000d: rethrow
   L_000f: nop
   L_0010: ret
   .try L_0001 to L_000b catch ConsoleUnitTest.DummyException handler L_000b to L_000f
}
MSIL
.method public hidebysig static void MethodThrowException2() cil managed
{
   .maxstack 1
   .locals init (
     [0] class ConsoleUnitTest.DummyException de)
   L_0000: nop
   L_0001: nop
   L_0002: call void ConsoleUnitTest.Program::DoLowLevelOperation()
   L_0007: nop
   L_0008: nop
   L_0009: leave.s L_000f
   L_000b: stloc.0
   L_000c: nop
   L_000d: ldloc.0
   L_000e: throw
   L_000f: nop
   L_0010: ret
   .try L_0001 to L_000b catch ConsoleUnitTest.DummyException handler L_000b to L_000f
}

The definition for "rethrow" and "throw" in IL are shown below:

  • rethrow: Rethrows the current exception
  • throw: Throws the exception Object currently on evaluation stack

So What Should We Do?

Now that we are clear about the difference, what should we do? Every time we manually throw a specific type of Exception, we should wrap the caught exception as InnerException:

C#
try
{
   throw new DummyException("A dummy exception message!");
}
catch (DummyException de)
{
   AnotherTypeOfException anotherTypeOfException =
            new AnotherTypeOfException("Customized exception message.", de)
   throw anotherTypeOfException;
}

When initializing AnotherTypeOfException we actually calls Exception's construcor "(String message, Exception innerException)", so finally, there will be no information loss.

There is one particular detail, when we wrote code similar to below, Resharper will warn us that it is redundant because "The catch statement may appear to be doing something, but it really isn't: all it's doing is throwing the exception (with the same stack information)", Resharper link.

228868/RedundantThrow1.png

228868/RedundantThrow2.png

Instead, if we wrote "throw de", in the above example, Resharper will NOT give you any warning, because now we know they are different, "throw de" will truncate the StackTrace information and rethrow the DemmyException instance.

Difference Between Parameterless Catch and Catch (Exception ex)

Before .NET Framework 2.0, Non-CLS-Compliant exceptions does not inherit from System.Exception, that means catch (Exception ex) cannot catch Non-CLS-Compliant exceptions thrown from for example COM or native C++ components; However, in .NET Framework 2.0, compiler will wrap those Non-CLS-Compliant exceptions into a specific Exception type: RuntimeWrappedException, it has a property: WrappedException to store a non-CLS-Compliant exception, results in statement "catch (Exception ex)" can catch all runtime exceptions.

Whereas this is configurable, the wrapping operation is by default on however could be turned off by applying RuntimeCompatibility attribute to your assembly, i.e., AssemblyInfo.cs.

C#
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = false)]

By specifying WrapNonExceptionThrows = false under RuntimeCompatibility attribute, non-CLS-Compliant exceptions will not be converted to System.Exception, so they will not be caught by catch (Exception ex) but can be caught by parameterless catch.

Further Reading

This article was originally posted at http://wayneye.com/Blog/Different-Between-Throw-Throw-EX

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) SAP Labs Shanghai
China China
Wayne is a software developer, Tech Lead and also a geek. He has more than 6 years' experience in Web development(server: ASP.NET (MVC), Web Service, IIS; Client: HTML/CSS/JavaScript/jQuery/AJAX), Windows development (Winform, Windows Service, WPF/Silverlight, Win32 API and WMI) and SQL Server. Deep understanding of GOF Design Patterns, S.O.L.i.D principle, MVC, MVVM, Domain Driven Design, SOA, REST and AOP.

Wayne's Geek Life http://WayneYe.com

Infinite passion on programming!

Comments and Discussions

 
GeneralIf I had a dollar ... Pin
CamBendy1-Aug-11 15:24
CamBendy1-Aug-11 15:24 
GeneralRe: If I had a dollar ... Pin
Wayne Ye1-Aug-11 15:38
Wayne Ye1-Aug-11 15:38 
Questionno Pin
hwuei.vip26-Jul-11 15:22
hwuei.vip26-Jul-11 15:22 
AnswerRe: no Pin
Wayne Ye26-Jul-11 16:30
Wayne Ye26-Jul-11 16:30 
GeneralRe: no Pin
hwuei.vip27-Jul-11 3:18
hwuei.vip27-Jul-11 3:18 
GeneralRe: no Pin
Wayne Ye27-Jul-11 16:47
Wayne Ye27-Jul-11 16:47 
GeneralRe: no Pin
hwuei.vip27-Jul-11 19:18
hwuei.vip27-Jul-11 19:18 
GeneralRe: no Pin
Wayne Ye27-Jul-11 22:01
Wayne Ye27-Jul-11 22:01 
GeneralMy vote of 5 Pin
ChunkyStool26-Jul-11 8:00
ChunkyStool26-Jul-11 8:00 
This is good to know.
GeneralRe: My vote of 5 Pin
Wayne Ye26-Jul-11 16:29
Wayne Ye26-Jul-11 16:29 
GeneralMy vote of 5 Pin
BrianBissell26-Jul-11 4:26
BrianBissell26-Jul-11 4:26 
GeneralRe: My vote of 5 Pin
Wayne Ye26-Jul-11 16:27
Wayne Ye26-Jul-11 16:27 
GeneralMy vote of 5 Pin
kobymeir26-Jul-11 0:24
kobymeir26-Jul-11 0:24 
GeneralRe: My vote of 5 Pin
Wayne Ye26-Jul-11 16:15
Wayne Ye26-Jul-11 16:15 
GeneralMy vote of 5 Pin
jfriedman25-Jul-11 9:54
jfriedman25-Jul-11 9:54 
GeneralRe: My vote of 5 Pin
Wayne Ye26-Jul-11 16:15
Wayne Ye26-Jul-11 16:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.