Monday, June 20, 2005 4:45 PM
Here is a mistake that I run into every now and then and thought I'd try to shed some light on it.
When rethrowing a caught exception, there are two different ways to do it. Each way has very specific repercussions to the data stored in the exception object.
First, you can use throw exceptionInstance; and second, you can also use throw; But what are the differences? When you throw a caught exception by actually throwing the exception instance, the first example, the stack trace for that exception starts at the point of the throw. When you just use the throw keyword without an exception instance, the second example, the CLR knows to rethrow the caught exception and the stack track for that exception continues back to where the exception was originally thrown. Let me show an example to make this more clear:
public class ExceptionTestA
{
public void OneA()
{
try
{
TwoA();
}
catch (Exception ex)
{
//Pretend we're logging this for trouble shooting
Console.WriteLine(ex.StackTrace);
}
}
public void TwoA()
{
ThreeA();
}
public void ThreeA()
{
try
{
FourA();
}
catch (Exception ex)
{
//Doing some processing
throw ex;
}
}
public void FourA()
{
FiveA();
}
public void FiveA()
{
throw new Exception("Exception A");
}
}
Notice that when the exception is rethrown in ThreeA(), its actually throwing the exception instance. When you call OneA() of this class, you'll get the following call stack written to the console:
at WebBrowserTesting.ExceptionTestA.ThreeA() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 38
at WebBrowserTesting.ExceptionTestA.TwoA() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 26
at WebBrowserTesting.ExceptionTestA.OneA() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 16
Now lets look at another class:
public class ExceptionTestB
{
public void OneB()
{
try
{
TwoB();
}
catch (Exception ex)
{
//Pretend we're logging this for trouble shooting
Console.WriteLine(ex.StackTrace);
}
}
public void TwoB()
{
ThreeB();
}
public void ThreeB()
{
try
{
FourB();
}
catch (Exception ex)
{
//Doing some processing
throw;
}
}
public void FourB()
{
FiveB();
}
public void FiveB()
{
throw new Exception("Exception B");
}
}
Pretty much the exact same code, except in ThreeB() I just call the throw keyword, without using the exception instance. This is what its stack trace looks like:
at WebBrowserTesting.ExceptionTestB.FiveB() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 96
at WebBrowserTesting.ExceptionTestB.FourB() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 91
at WebBrowserTesting.ExceptionTestB.ThreeB() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 85
at WebBrowserTesting.ExceptionTestB.TwoB() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 73
at WebBrowserTesting.ExceptionTestB.OneB() in c:\dev play\webbrowsertesting\exceptiontest.cs:line 63
See the difference? When you just call the throw keyword, you get a stack trace going all the way back to the original exception being thrown. This is vital for usable troubleshooting!