Click here to Skip to main content
Click here to Skip to main content

Exception handling particulars in C#

By , 28 Jul 2011
 

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 code snippet below:

 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 higher level, and we may also saw another way in a little different:

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

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

 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 handle it in different way mentioned above:

 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: 

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:

 .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
 }
 .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 showing 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:

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

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

There is one particular details, when we wrote code similar with below, Resharper will warning us 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

RedundantThrow1.png

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

Different 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 an 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 how ever could be turn off be applying RuntimeCompatibility attribute to your assembly, i.e. AssemblyInfo.cs.

[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  

Exception Handling on MSDN
http://msdn.microsoft.com/en-us/library/ms229005.aspx

Using COM Object
http://insideaspnet.com/index/using-com-objects/ 

Difference between "throw" and "throw ex" in .NET
http://geekswithblogs.net/sdorman/archive/2007/08/20/Difference-between-quotthrowquot-and-quotthrow-exquot-in-.NET.aspx

Also posted at my blog - Wayne's Geek Life: 
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)

About the Author

Wayne Ye
Software Developer (Senior) SAP Labs Shanghai
China China
Member
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!

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralIf I had a dollar ...memberCamBendy1 Aug '11 - 15:24 
for every line of code I have "fixed" in the past because some developer has ignorantly decided to not learn how it works, and call the throw the exception again rather than rethrow it, thus losing the call stack..... Mad | :mad:
 
Well, I guess I wouldn't have to program any more! At least these maroons keep me in a job. Global search and replace is your friend! Cool | :cool:
 
Thanks for an article that so succinctly states the issue and highlights the difference. Thumbs Up | :thumbsup:
I came, I saw, I ran away!

GeneralRe: If I had a dollar ...memberWayne Ye1 Aug '11 - 15:38 
Thank you for the comments! Wish it helps more or lessSmile | :)
Happy CodingSmile | :)
Wayne Ye - Software Developer/Tech Lead & Geek
 
Wayne's Geek Life http://WayneYe.com
Infinite passion one programming!

Questionnomemberhwuei.vip26 Jul '11 - 15:22 
i use "throw",but the ILCode still "rethrow"! why?
AnswerRe: nomemberWayne Ye26 Jul '11 - 16:30 
Hi hwuei,
It couldn't be. Could you paste your code here so that I can have a try? Thank you!
Happy CodingSmile | :)
Wayne Ye - Software Developer/Tech Lead & Geek
 
Wayne's Geek Life http://WayneYe.com
Infinite passion one programming!

GeneralRe: nomemberhwuei.vip27 Jul '11 - 3:18 
Just simple code like this:
 

 
namespace TestExp
{
class Program
{
static void Main(string[] args)
{
B a = new B();
 
try
{
a.Show();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
 
Console.ReadKey();
}
}
 
public class B
{
public void Show()
{
try
{
int a = 0;
 
int j = 11 / a;
}
catch
{
throw;
}
}
}
}
 

 
I saw the ILCode is "rethrow". I don't know why.Please help me.Thanks.
GeneralRe: nomemberWayne Ye27 Jul '11 - 16:47 
Hi hwuei.vip,
You might didn't read my post carefullySmile | :)
 
In C#, after C# compiler combines code snippet below into CIL, it will be "rethrow", indicates "Rethrows the current exception. ".
try
{
}
catch
{
    throw;
}
In fact so does:
try
{
}
catch (Exception ex)
{
    throw;
}
 
You can refer more on Exception handling Official MSDN page: http://msdn.microsoft.com/en-us/library/ms229005.aspx[^]
 
Please feel free to let me know whether this is clear to you, thanks!
Happy CodingSmile | :)
Wayne Ye - Software Developer/Tech Lead & Geek
 
Wayne's Geek Life http://WayneYe.com
Infinite passion one programming!

GeneralRe: nomemberhwuei.vip27 Jul '11 - 19:18 
I got it. My mistake.It should be 'rethrow'. Thanks a lot!
GeneralRe: nomemberWayne Ye27 Jul '11 - 22:01 
You are very welcomeSmile | :)
Happy CodingSmile | :)
Wayne Ye - Software Developer/Tech Lead & Geek
 
Wayne's Geek Life http://WayneYe.com
Infinite passion one programming!

GeneralMy vote of 5memberChunkyStool26 Jul '11 - 8:00 
This is good to know.
GeneralRe: My vote of 5memberWayne Ye26 Jul '11 - 16:29 
Thank you for the commentsSmile | :)
Happy CodingSmile | :)
Wayne Ye - Software Developer/Tech Lead & Geek
 
Wayne's Geek Life http://WayneYe.com
Infinite passion one programming!

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 28 Jul 2011
Article Copyright 2011 by Wayne Ye
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid