Scott Dorman

ephemeral segment

  Home  |   Contact  |   Syndication    |   Login
  566 Posts | 9 Stories | 568 Comments | 51 Trackbacks

News


Post Categories

Image Galleries



Creative Commons License


Microsoft MVP


MCP Profile


Locations of visitors to this page

Subscribers to this feed

TwitterCounter for @sdorman

View blog authority

Add to Technorati Favorites

Windows Live Alerts

AddThis Social Bookmark Button

LinkedIn profile

Community Credit profile

The Code Project

Follow me on Twitter

Get Free Shots from Snap.com

Community Credit Hall of Fame

Get Feedghost

Xobni outlook add-in for your inbox

Windows Live Translator


Support This Site

Tag Cloud


Article Categories

Archives

Post Categories

Image Galleries

Exception handling seems to be a common problem for .NET developers, particularly younger developers. We pretty much all know that you should wrap operations that have the potential for failing in a try/catch block if you are interested in being able to do something about the error that occurred. I'm not going to talk about the rules and guidelines for using exception handling. Instead I'm going to focus on a particular aspect of exception handling, which I tend to call exception bubbling.

Exception bubbling means that even though you are catching the exception and doing something with it, you want that exception to "bubble" up from your code to the calling code so it has a chance to do something with that exception. This is a fairly common scenario, but it has the potential to cause some major problems when you are debugging.

I'm sure most of the exception bubbling code you've seen looks similar to this

   1: try
   2: {
   3:     // do some operation that can fail
   4: }
   5: catch (Exception ex)
   6: {
   7:     // do some local cleanup
   8:     throw ex;
   9: }

This code looks perfectly reasonable and does the job. It properly catches the exception, does some local cleanup and then bubbles the exception up the chain. (A side note here is that you really shouldn't catch a general exception like this. I'm doing this for simplicity in the examples, but you should be catching specific exceptions and only those that you can do something about.)

However, how  many of you have seen code that looks like this

   1: try
   2: {
   3:     // do some operation that can fail
   4: }
   5: catch (Exception ex)
   6: {
   7:     // do some local cleanup
   8:     throw;
   9: }

There is a subtle difference between these two calls that won't be apparent until you are trying to debug the problem. That difference is in the stack trace information that gets sent with the exception.

In the first case, the stack trace is truncated below the method that failed. What this means is that when you look at the stack trace, it will look as if the exception originated in your code. This isn't always the case, particularly if you are bubbling up a CLR generated exception (like a SqlException). This is a problem known as "breaking the stack", because you no longer have the full stack trace information. This happens because you are in essence creating a new exception to throw. 

By using "throw" by itself, you preserve the stack trace information. You can confirm this by looking at the IL generated for these two code blocks. This makes the difference very obvious since in the first example the IL instruction called is "throw" while in the second the instruction is called "rethrow".

Before you run and change all of your code, there are still places where "throw ex" is appropriate. There are times when you want to add information to the exception that was caught or change it into a more meaningful exception. In these instances you actually want a new exception to be thrown. Again, there are two ways you can do this. The most common way that I have seen is

   1: try
   2: {
   3:     // do some operation that can fail
   4: }
   5: catch (Exception ex)
   6: {
   7:     // do some local cleanup
   8:     throw new ApplicationException("operation failed!");
   9: }

However, this still suffers the problem of breaking the stack. Here you are generating a completely new exception and loosing any of the stack trace information from the original exception. What you really want to do is

   1: try
   2: {
   3:     // do some operation that can fail
   4: }
   5: catch (Exception ex)
   6: {
   7:     // do some local cleanup
   8:     throw new ApplicationException("operation failed!", ex);
   9: }

By passing the original exception to the ApplicationException you are preserving the original exception, and it's stack trace information, as the inner exception to your ApplicationException.

To wrap everything up

    1. Only catch exceptions if they are important to you and you need to do some sort of cleanup as a result.
    2. If you need to bubble an exception up the chain, use "throw" by itself.
    3. If you need to add information to the exception or repackage it, always pass the original exception as the inner exception.
posted on Monday, August 20, 2007 11:26 AM

Feedback

# re: Difference between "throw" and "throw ex" in .NET 8/21/2007 11:20 PM David
Nice post. Thanks for clearing this up!

# re: Difference between "throw" and "throw ex" in .NET 9/21/2007 2:54 AM Bhabani
This article is really useful. This piece of information has never crossed my mind. Thanks for this wonderful article.

# re: Difference between "throw" and "throw ex" in .NET 12/29/2007 6:29 AM Vikas Goyal
Thanks, Nicely explained.

# re: Difference between "throw" and "throw ex" in .NET 1/17/2008 2:43 AM Donniel Thomas
Hi,

Great article! I had a question for you: You say that one should let the exception bubble up, unless it can be handled. But wouldn't it be better to always catch the error and display a user-friendly message to the user, and log the error? A run-time exception will just frighten and confuse the user.

Or do you recommend letting the exception bubble up, and creating a generic error page, which is displayed for all errors, and does logging, etc.?

Thanks and regards,
Donniel

# re: Difference between "throw" and "throw ex" in .NET 1/17/2008 11:37 PM Scott
@Donniel, The problem with catching the error and displaying it to the user is that the user may not actually need to know about the error and/or be able to do anything about it. If you just catch and log the error then you can be potentially hiding the problem and cause other problems in the long run.

If you've done a good job of defensive programming the most common exceptions will be handled somewhere in your call chain. Creating a generic error page for any unhandled exceptions isn't a bad idea as long as you don't use it as a "catch all" for any exception.

# re: Difference between "throw" and "throw ex" in .NET 2/20/2008 1:56 PM Sebina Mariadhas
Good article !! Clearly explained the difference.

# re: Difference between "throw" and "throw ex" in .NET 4/28/2008 7:01 AM TATA
Wonderful article.Really nice.Thanks for the clarification

# re: Difference between "throw" and "throw ex" in .NET 5/8/2008 4:54 AM Nishanth Nair
Nice article. Explanation is superb with sweet and simple code snippets.

Nishanth
www.dotnetrocks.wordpress.com

# re: Difference between "throw" and "throw ex" in .NET 5/25/2008 3:17 PM Scott
@Sebina, @TATA, @Nishanth: Thanks!

# re: Difference between "throw" and "throw ex" in .NET 8/1/2008 3:14 PM Mathew
I have a question for you scott. What if we throw a new exception and add the ex.stacktrace along with the ex.message?

# re: Difference between "throw" and "throw ex" in .NET 8/2/2008 5:18 PM Scott
Mathew, the best option for throwing a new exception is to include the original one as a nested exception. This is actually cleaner than adding the stack trace data to the message of the new exception as it keeps the message cleaner and keeps the information where debuggers and support people are most likely to expect it.

# re: Difference between "throw" and "throw ex" in .NET 9/19/2008 6:38 AM Hassan Khan
Very simple to understand but excellent at the same time !!

# re: Difference between "throw" and "throw ex" in .NET 2/25/2009 10:33 PM Virendra Singh
Wonderful! informative and crisp.

Post Feedback

Title:
Name:
Email: (never displayed)
Url:
Comments: