I'll throw, you catch {}

Every few months I see this topic re-emerge in some fashion, and lately it has done the same internally here at Microsoft. So, I thought I’d share some various pearls of wisdom on some exception handling characteristics and best practices. Many of this below summarizes the opinions of others internally, including thoughts of various individuals on the CLR and VC# teams.

So the specific question is: what is different in the following code blocks? (Look at the throw statements.)

try
{
    //logic that may throw
    //an exception
}
catch (Exception e)
{
    throw;
}


And:

try
{
    //logic that may throw
    //an exception
}
catch (Exception e)
{
    throw e;
}


The specific difference is that "throw;" will preserve the stack trace, whereas "throw e;" throws the same exception but will not preserve the original exception's stack trace information. Generally speaking, if you have code like this, you'll want the former if you want any hope of tracing the call stack to the point where the original exception was thrown. Some people have implemented this functionality by wrapping the original exception in a new exception. This can be handy if you want to preserve the stack trace information but throw a completely new error:

try
{
    //logic that may throw
    //an exception
}
catch (Exception e)
{
    throw new MyCustomException(e);
}


One of the contributors to the thread pointed out an inaccuracy in the book "The Common Language Infrastucture Annotated Standard" (James S. Miller, Susann Ragsdale) that states:

"A rethrow [ed: the first example] does not change the stack trace in the object. Rethrow means that you caught an exception and then decided to resume processing it. This would not, then, change the captured stack trace information."

This is actually not completely accurate - the rethrow will push the point of the rethrow onto the stack trace. It's a minor clarification and it makes sense (to me), but it's not a "pretend we never caught the exception" operation. This does raise a few items regarding best practices, and it's important to note that a throw and rethrow are different IL operations. This behavior is quite different from Java; in C#, the IL instruction "rethrow" is invoked by a "throw;" statement (no wonder it's confusing).

First is the performance implication. Exception handling and subsequently rethrowing exceptions are expensive operations. This is more from a theory and understanding of the framework point of view. In practice, you would use .NET's Structured Exception Handling (SEH) for what it's there for: handling error conditions or unexpected behavior. You wouldn't want to throw an exception for an expected error condition ... for example, in general you wouldn't do something like:

//excuse the lame validation implementation
if (txtZipCode.Length != 5)
{
    throw new System.ArgumentOutOfRangeException("Invalid zip.");
}


In my made up example, I'm mentally thinking of a webform that validates the zip. I'm sure there are examples where throwing an exception of this type is more feasible, such as backend jobs that don't anticipate these problems and where the data is already normalized -- therefore, a true error has occurred. At this point, we can either handle the error, or not.

This leads me to the next point that was discussed: consider carefully why exceptions are getting caught and rethrown. After all, the purpose of the catch is to handle the exception. While it's certainly an error condition, catching it implies at least a planned-for condition, or possible condition that can be handled. If the error is simply rethrown, what is being accomplished? Similarly, it's usually a bad idea to only use a catch-all (catching every type of exception in a single catch) because, depending on the code, you may catch exceptions the code isn't prepared to handle.

Sometimes, though, I've found myself doing exactly this. Very often, I'll rethrow errors in debug builds (using precompiler directives). For example:

try
{
    //logic that may throw
    //an exception
}
catch (Exception e)
{
#if DEBUG
    throw;
#endif
    return null; // or whatever is appropriate... custom exception?

}


Most of the time, these type of routines simply return a non-vital control or set of data, so I intentionally want to eat the error in a production environment (though it's usually logged). For example, the random quote on my site -- if there's a caching issue or the database is down, there's no point in redirecting to an error page.

In the end, I'm struggling with good design principals. With a host of utility classes, is it better to adopt a paradigm that bubbles exceptions out of the class? (If so, then virtually every exception gets rethrown or not caught to begin with -- this doesn't seem too robust.) How do you correctly make the distinction in base or utility classes that certain errors can be handled vs thrown? It seems you have to take the client code into consideration, but that's not a good OOP paradigm, either.

In the end I'm thinking that for any application of reasonable complexity, a collection of classes will have to share a common custom exception library, to make error throwing and handling appropriate in a way that client code is completely decoupled, yet maintains robust error handling through those custom exceptions. And then I figured: there must be a design pattern or app block out there, and sure enough -- MSDN has it. Check it out here:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/ehab.asp

I'm amazed I hadn't explored this area until now -- my exception handling up to this point has been fairly flat... thoughts? Ideas?
Comments are closed

My Apps

Dark Skies Astrophotography Journal Vol 1 Explore The Moon
Mars Explorer Moons of Jupiter Messier Object Explorer
Brew Finder Earthquake Explorer Venus Explorer  

My Worldmap

Month List