What are the best practices to consider when catching exceptions and re-throwing them? I want to make sure that the Exception object's InnerException and stack trace are preserved. Is there a difference between the following code blocks in the way they handle this?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Vs:
try
{
//some code
}
catch
{
throw;
}
The way to preserve the stack trace is through the use of the throw; This is valid as well
try {
// something that bombs here
} catch (Exception ex)
{
throw;
}
throw ex; is basically like throwing an exception from that point, so the stack trace would only go to where you are issuing the throw ex; statement.
Mike is also correct, assuming the exception allows you to pass an exception (which is recommended).
Karl Seguin has a great write up on exception handling in his foundations of programming e-book as well, which is a great read.
Edit: Working link to Foundations of Programming pdf. Just search the text for "exception".
If you throw a new exception with the initial exception you will preserve the initial stack trace too..
try{
}
catch(Exception ex){
throw new MoreDescriptiveException("here is what was happening", ex);
}
Actually, there are some situations which the throw statment will not preserve the StackTrace information. For example, in the code below:
try
{
int i = 0;
int j = 12 / i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
The StackTrace will indicate that line 54 raised the exception, although it was raised at line 47.
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowIncomplete() in Program.cs:line 54
at Program.Main(String[] args) in Program.cs:line 106
In situations like the one described above, there are two options to preseve the original StackTrace:
Calling the Exception.InternalPreserveStackTrace
As it is a private method, it has to be invoked by using reflection:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
I has a disadvantage of relying on a private method to preserve the StackTrace information. It can be changed in future versions of .NET Framework. The code example above and proposed solution below was extracted from Fabrice MARGUERIE weblog.
Calling Exception.SetObjectData
The technique below was suggested by Anton Tykhyy as answer to In C#, how can I rethrow InnerException without losing stack trace question.
static void PreserveStackTrace (Exception e)
{
var ctx = new StreamingContext (StreamingContextStates.CrossAppDomain) ;
var mgr = new ObjectManager (null, ctx) ;
var si = new SerializationInfo (e.GetType (), new FormatterConverter ()) ;
e.GetObjectData (si, ctx) ;
mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData
mgr.DoFixups () ; // ObjectManager calls SetObjectData
// voila, e is unmodified save for _remoteStackTraceString
}
Although, it has the advantage of relying in public methods only it also depends on the following exception constructor (which some exceptions developed by 3rd parties do not implement):
protected Exception(
SerializationInfo info,
StreamingContext context
)
In my situation, I had to choose the first approach, because the exceptions raised by a 3rd-party library I was using didn't implement this constructor.
When you throw ex, you're essentially throwing a new exception, and will miss out on the original stack trace information. throw is the preferred method.
The rule of thumb is to avoid Catching and Throwing the basic Exception object. This forces you to be a little smarter about exceptions; in other words you should have an explicit catch for a SqlException so that your handling code doesn't do something wrong with a NullReferenceException.
In the real world though, catching and logging the base exception is also a good practice, but don't forget to walk the whole thing to get any InnerExceptions it might have.
Nobody has explained the difference between ExceptionDispatchInfo.Capture( ex ).Throw() and a plain throw, so here it is. However, some people have noticed the problem with throw.
The complete way to rethrow a caught exception is to use ExceptionDispatchInfo.Capture( ex ).Throw() (only available from .Net 4.5).
Below there are the cases necessary to test this:
1.
void CallingMethod()
{
//try
{
throw new Exception( "TEST" );
}
//catch
{
// throw;
}
}
2.
void CallingMethod()
{
try
{
throw new Exception( "TEST" );
}
catch( Exception ex )
{
ExceptionDispatchInfo.Capture( ex ).Throw();
throw; // So the compiler doesn't complain about methods which don't either return or throw.
}
}
3.
void CallingMethod()
{
try
{
throw new Exception( "TEST" );
}
catch
{
throw;
}
}
4.
void CallingMethod()
{
try
{
throw new Exception( "TEST" );
}
catch( Exception ex )
{
throw new Exception( "RETHROW", ex );
}
}
Case 1 and case 2 will give you a stack trace where the source code line number for the CallingMethod method is the line number of the throw new Exception( "TEST" ) line.
However, case 3 will give you a stack trace where the source code line number for the CallingMethod method is the line number of the throw call. This means that if the throw new Exception( "TEST" ) line is surrounded by other operations, you have no idea at which line number the exception was actually thrown.
Case 4 is similar with case 2 because the line number of the original exception is preserved, but is not a real rethrow because it changes the type of the original exception.
You should always use "throw;" to rethrow the exceptions in .NET,
Refer this,
http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
Basically MSIL (CIL) has two instructions - "throw" and "rethrow":
C#'s "throw ex;" gets compiled into MSIL's "throw"
C#'s "throw;" - into MSIL "rethrow"!
Basically I can see the reason why "throw ex" overrides the stack trace.
A few people actually missed a very important point - 'throw' and 'throw ex' may do the same thing but they don't give you a crucial piece of imformation which is the line where the exception happened.
Consider the following code:
static void Main(string[] args)
{
try
{
TestMe();
}
catch (Exception ex)
{
string ss = ex.ToString();
}
}
static void TestMe()
{
try
{
//here's some code that will generate an exception - line #17
}
catch (Exception ex)
{
//throw new ApplicationException(ex.ToString());
throw ex; // line# 22
}
}
When you do either a 'throw' or 'throw ex' you get the stack trace but the line# is going to be #22 so you can't figure out which line exactly was throwing the exception (unless you have only 1 or few lines of code in the try block). To get the expected line #17 in your exception you'll have to throw a new exception with the original exception stack trace.
You may also use:
try
{
// Dangerous code
}
finally
{
// clean up, or do nothing
}
And any exceptions thrown will bubble up to the next level that handles them.
I would definitely use:
try
{
//some code
}
catch
{
//you should totally do something here, but feel free to rethrow
//if you need to send the exception up the stack.
throw;
}
That will preserve your stack.
FYI I just tested this and the stack trace reported by 'throw;' is not an entirely correct stack trace. Example:
private void foo()
{
try
{
bar(3);
bar(2);
bar(1);
bar(0);
}
catch(DivideByZeroException)
{
//log message and rethrow...
throw;
}
}
private void bar(int b)
{
int a = 1;
int c = a/b; // Generate divide by zero exception.
}
The stack trace points to the origin of the exception correctly (reported line number) but the line number reported for foo() is the line of the throw; statement, hence you cannot tell which of the calls to bar() caused the exception.
Related
Good day!
i write simple console program. It have func Main () and class Adapter;
some simple code that explains how it works:
void Main()
{
try
{
Work(array);
//subcribing at some events;
Application.Run();
}
catch(Exception ex)
{
//write to log;
}
}
class Adapter
{
....
public void GetSomething()
{
try
{
...some work and exception goes here;
}
catch(Exception ex)
{
//catch exception and do Work:
Work(array);
}
}
}
When exception goes- it catches at GetSomething. So,i write some values.But i need that the program still running after exception.
But after catch in GetSomething method it goes to Exception ex at Main func and program exits;
How to do that program will still running after catch exception in GetSomething method?
Thank you!
If what you want is to catch an exception and continue execution at the point of failure (which might be several layers down in the call stack) and possibly retrying the failed statement, you're pretty much out of luck.
Once your catch clause is invoked, the stack has been unwound up to that point. You can deal with the exception in some way and then choose zero or one of
Continuing the exceptio via throw ;
Re-throwing the exception via throw e;
Throwing a new exception via throw new SomeException();
If didn't choose one of the above, execution continues at the point following the try/catch/finally block. For example:
try
{
DoSomethingThatMightThrowAnException() ;
}
catch ( Exception e )
{
DoSomethingToHandleTheExceptionHere() ;
// Then, choose zero or one of the following:
throw ; // current exception is continue with original stack trace
throw e ; // current exception is re-thrown with new stack trace originating here
throw new Exception() ; // a new exception is thrown with its stack trace originating here
throw new Exception(e) ; // a new exception is thrown as above, with the original exception as the inner exception
}
finally
{
// regardless of whether or not an exception was thrown,
// code in the finally block is always executed after the try
// (and the catch block, if it was invoked)
}
// if you didn't throw, execution continues at this point.
If you don't do one of the above, execution continues at the statement following the try/catch/finally block.
The best you can do as far as retrying is something like this:
// retry operation at most 3
int number_of_retries = 5 ;
for ( int i = 0 ; i < number_of_retries ; ++i )
{
try
{
DoSomethingThatMightThrowAnException() ;
break ; // exit the loop on success
}
catch( Exception e )
{
Log.Error("well...that didn't work") ;
ExecuteRecoveryCode() ;
}
}
This behavior is not possible in .NET. When an exception is thrown, control exits the current point and continues onto the first catch statement it can find in the call stack, or exits the program, thus eliminating execution of the call stack up to that point. This is part of the definition of exceptional behavior.
You can instead break down the process being done by Work and process each item one at a time to enable the same effect as what you're asking. In other words, instead of Work(array), try
foreach(var item in array)
{
try { WorkSingle(item); }
catch { continue; }
}
You can use try, catch and finally:
http://www.dotnetperls.com/finally
http://msdn.microsoft.com/es-es/library/dszsf989.aspx
I rethrow an exception with "throw;", but the stacktrace is incorrect:
static void Main(string[] args) {
try {
try {
throw new Exception("Test"); //Line 12
}
catch (Exception ex) {
throw; //Line 15
}
}
catch (Exception ex) {
System.Diagnostics.Debug.Write(ex.ToString());
}
Console.ReadKey();
}
The right stacktrace should be:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 12
But I get:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 15
But line 15 is the position of the "throw;". I have tested this with .NET 3.5.
Throwing twice in the same method is probably a special case - I've not been able to create a stack trace where different lines in the same method follow each other. As the word says, a "stack trace" shows you the stack frames that an exception traversed. And there is only one stack frame per method call!
If you throw from another method, throw; will not remove the entry for Foo(), as expected:
static void Main(string[] args)
{
try
{
Rethrower();
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
Console.ReadKey();
}
static void Rethrower()
{
try
{
Foo();
}
catch (Exception ex)
{
throw;
}
}
static void Foo()
{
throw new Exception("Test");
}
If you modify Rethrower() and replace throw; by throw ex;, the Foo() entry in the stack trace disappears. Again, that's the expected behavior.
It's something that can be considered as expected.
Modifying stack trace is usual case if you specify throw ex;, FxCop will than notify you that stack is modified. In case you make throw;, no warning is generated, but still, the trace will be modified.
So unfortunately for now it's the best not to catch the ex or throw it as an inner one.
I think it should be considered as a Windows impact or smth like that - edited.
Jeff Richter describes this situation in more detail in his "CLR via C#":
The following code throws the same
exception object that it caught and
causes the CLR to reset its starting
point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw e; // CLR thinks this is where exception originated.
// FxCop reports this as an error
}
}
In contrast, if you re-throw an
exception object by using the throw
keyword by itself, the CLR doesn’t
reset the stack’s starting point. The
following code re-throws the same
exception object that it caught,
causing the CLR to not reset its
starting point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw; // This has no effect on where the CLR thinks the exception
// originated. FxCop does NOT report this as an error
}
}
In fact, the only difference between
these two code fragments is what the
CLR thinks is the original location
where the exception was thrown.
Unfortunately, when you throw or
rethrow an exception, Windows does
reset the stack’s starting point. So
if the exception becomes unhandled,
the stack location that gets reported
to Windows Error Reporting is the
location of the last throw or
re-throw, even though the CLR knows
the stack location where the original
exception was thrown. This is
unfortunate because it makes debugging
applications that have failed in the
field much more difficult. Some
developers have found this so
intolerable that they have chosen a
different way to implement their code
to ensure that the stack trace truly
reflects the location where an
exception was originally thrown:
private void SomeMethod() {
Boolean trySucceeds = false;
try {
...
trySucceeds = true;
}
finally {
if (!trySucceeds) { /* catch code goes in here */ }
}
}
This is a well known limitation in the Windows version of the CLR. It uses Windows' built-in support for exception handling (SEH). Problem is, it is stack frame based and a method has only one stack frame. You can easily solve the problem by moving the inner try/catch block into another helper method, thus creating another stack frame. Another consequence of this limitation is that the JIT compiler won't inline any method that contains a try statement.
How can I preserve the REAL stacktrace?
You throw a new exception, and include the original exception as the inner exception.
but that's Ugly... Longer... Makes you choice the rigth exception to throw....
You are wrong about the ugly but right about the other two points. The rule of thumb is: don't catch unless you are going to do something with it, like wrap it, modify it, swallow it, or log it. If you decide to catch and then throw again, make sure you are doing something with it, otherwise just let it bubble up.
You may also be tempted to put a catch simply so you can breakpoint within the catch, but the Visual Studio debugger has enough options to make that practice unnecessary, try using first chance exceptions or conditional breakpoints instead.
Edit/Replace
The behavior is actually different, but subtilely so. As for why the behavior if different, I'll need to defer to a CLR expert.
EDIT: AlexD's answer seems to indicate that this is by design.
Throwing the exception in the same method that catches it confuses the situation a little, so let's throw an exception from another method:
class Program
{
static void Main(string[] args)
{
try
{
Throw();
}
catch (Exception ex)
{
throw ex;
}
}
public static void Throw()
{
int a = 0;
int b = 10 / a;
}
}
If throw; is used, the callstack is (line numbers replaced with code):
at Throw():line (int b = 10 / a;)
at Main():line (throw;) // This has been modified
If throw ex; is used, the callstack is:
at Main():line (throw ex;)
If exception is not caught, the callstack is:
at Throw():line (int b = 10 / a;)
at Main():line (Throw())
Tested in .NET 4 / VS 2010
There is a duplicate question here.
As I understand it - throw; is compiled into 'rethrow' MSIL instruction and it modifies the last frame of the stack-trace.
I would expect it to keep the original stack-trace and add the line where it has been re-thrown, but apparently there can only be one stack frame per method call.
Conclusion: avoid using throw; and wrap your exception in a new one on re-throwing - it's not ugly, it's best practice.
You can preserve stack trace using
ExceptionDispatchInfo.Capture(ex);
Here is code sample:
static void CallAndThrow()
{
throw new ApplicationException("Test app ex", new Exception("Test inner ex"));
}
static void Main(string[] args)
{
try
{
try
{
try
{
CallAndThrow();
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// rollback tran, etc
dispatchException.Throw();
}
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// other rollbacks
dispatchException.Throw();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
The output will be something like:
Test app ex
Test inner ex
at TestApp.Program.CallAndThrow() in D:\Projects\TestApp\TestApp\Program.cs:line 19
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 30
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 38
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 47
OK, there seems to be a bug in the .NET Framework, if you throw an exception, and rethrow it in the same method, the original line number is lost (it will be the last line of the method).
Fortunatelly, a clever guy named Fabrice MARGUERIE found a solution to this bug. Below is my version, which you can test in this .NET Fiddle.
private static void RethrowExceptionButPreserveStackTrace(Exception exception)
{
System.Reflection.MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
throw exception;
}
Now catch the exception as usually, but instead of throw; just call this method, and voila, the original line number will be preserved!
Not sure whether this is by design, but I think it has always been like that.
If the original throw new Exception is in a separate method, then the result for throw should have the original method name and line number and then the line number in main where the exception is re-thrown.
If you use throw ex, then the result will just be the line in main where the exception is rethrow.
In other words, throw ex loses all the stacktrace, whereas throw preserves the stack trace history (ie details of the lower level methods). But if your exception is generated by the same method as your rethrow, then you can lose some information.
NB. If you write a very simple and small test program, the Framework can sometimes optimise things and change a method to be inline code which means the results may differ from a 'real' program.
Do you want your right line number? Just use one try/catch per method. In systems, well... just in the UI layer, not in logic or data access, this is very annoying, because if you need database transactions, well, they shouldn't be in the UI layer, and you won't have the right line number, but if you don't need them, don't rethrow with nor without an exception in catch...
5 minutes sample code:
Menu File -> New Project, place three buttons, and call the following code in each one:
private void button1_Click(object sender, EventArgs e)
{
try
{
Class1.testWithoutTC();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC1();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button3_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC2();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
Now, create a new Class:
class Class1
{
public int a;
public static void testWithoutTC()
{
Class1 obj = null;
obj.a = 1;
}
public static void testWithTC1()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch
{
throw;
}
}
public static void testWithTC2()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch (Exception ex)
{
throw ex;
}
}
}
Run... the first button is beautiful!
I think this is less a case of stack trace changing and more to do with the way the line number for the stack trace is determined. Trying it out in Visual Studio 2010, the behaviour is similar to what you would expect from the MSDN documentation: "throw ex;" rebuilds the stack trace from the point of this statement, "throw;" leaves the stack trace as it as, except that where ever the exception is rethrown, the line number is the location of the rethrow and not the call the exception came through.
So with "throw;" the method call tree is left unaltered, but the line numbers may change.
I've come across this a few times, and it may be by design and just not documented fully. I can understand why they may have done this as the rethrow location is very useful to know, and if your methods are simple enough the original source would usually be obvious anyway.
As many other people have said, it usually best to not catch the exception unless you really have to, and/or you are going to deal with it at that point.
Interesting side note: Visual Studio 2010 won't even let me build the code as presented in the question as it picks up the divide by zero error at compile time.
That is because you catched the Exception from Line 12 and have rethrown it on Line 15, so the Stack Trace takes it as cash, that the Exception was thrown from there.
To better handle exceptions, you should simply use try...finally, and let the unhandled Exception bubble up.
I rethrow an exception with "throw;", but the stacktrace is incorrect:
static void Main(string[] args) {
try {
try {
throw new Exception("Test"); //Line 12
}
catch (Exception ex) {
throw; //Line 15
}
}
catch (Exception ex) {
System.Diagnostics.Debug.Write(ex.ToString());
}
Console.ReadKey();
}
The right stacktrace should be:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 12
But I get:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 15
But line 15 is the position of the "throw;". I have tested this with .NET 3.5.
Throwing twice in the same method is probably a special case - I've not been able to create a stack trace where different lines in the same method follow each other. As the word says, a "stack trace" shows you the stack frames that an exception traversed. And there is only one stack frame per method call!
If you throw from another method, throw; will not remove the entry for Foo(), as expected:
static void Main(string[] args)
{
try
{
Rethrower();
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
Console.ReadKey();
}
static void Rethrower()
{
try
{
Foo();
}
catch (Exception ex)
{
throw;
}
}
static void Foo()
{
throw new Exception("Test");
}
If you modify Rethrower() and replace throw; by throw ex;, the Foo() entry in the stack trace disappears. Again, that's the expected behavior.
It's something that can be considered as expected.
Modifying stack trace is usual case if you specify throw ex;, FxCop will than notify you that stack is modified. In case you make throw;, no warning is generated, but still, the trace will be modified.
So unfortunately for now it's the best not to catch the ex or throw it as an inner one.
I think it should be considered as a Windows impact or smth like that - edited.
Jeff Richter describes this situation in more detail in his "CLR via C#":
The following code throws the same
exception object that it caught and
causes the CLR to reset its starting
point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw e; // CLR thinks this is where exception originated.
// FxCop reports this as an error
}
}
In contrast, if you re-throw an
exception object by using the throw
keyword by itself, the CLR doesn’t
reset the stack’s starting point. The
following code re-throws the same
exception object that it caught,
causing the CLR to not reset its
starting point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw; // This has no effect on where the CLR thinks the exception
// originated. FxCop does NOT report this as an error
}
}
In fact, the only difference between
these two code fragments is what the
CLR thinks is the original location
where the exception was thrown.
Unfortunately, when you throw or
rethrow an exception, Windows does
reset the stack’s starting point. So
if the exception becomes unhandled,
the stack location that gets reported
to Windows Error Reporting is the
location of the last throw or
re-throw, even though the CLR knows
the stack location where the original
exception was thrown. This is
unfortunate because it makes debugging
applications that have failed in the
field much more difficult. Some
developers have found this so
intolerable that they have chosen a
different way to implement their code
to ensure that the stack trace truly
reflects the location where an
exception was originally thrown:
private void SomeMethod() {
Boolean trySucceeds = false;
try {
...
trySucceeds = true;
}
finally {
if (!trySucceeds) { /* catch code goes in here */ }
}
}
This is a well known limitation in the Windows version of the CLR. It uses Windows' built-in support for exception handling (SEH). Problem is, it is stack frame based and a method has only one stack frame. You can easily solve the problem by moving the inner try/catch block into another helper method, thus creating another stack frame. Another consequence of this limitation is that the JIT compiler won't inline any method that contains a try statement.
How can I preserve the REAL stacktrace?
You throw a new exception, and include the original exception as the inner exception.
but that's Ugly... Longer... Makes you choice the rigth exception to throw....
You are wrong about the ugly but right about the other two points. The rule of thumb is: don't catch unless you are going to do something with it, like wrap it, modify it, swallow it, or log it. If you decide to catch and then throw again, make sure you are doing something with it, otherwise just let it bubble up.
You may also be tempted to put a catch simply so you can breakpoint within the catch, but the Visual Studio debugger has enough options to make that practice unnecessary, try using first chance exceptions or conditional breakpoints instead.
Edit/Replace
The behavior is actually different, but subtilely so. As for why the behavior if different, I'll need to defer to a CLR expert.
EDIT: AlexD's answer seems to indicate that this is by design.
Throwing the exception in the same method that catches it confuses the situation a little, so let's throw an exception from another method:
class Program
{
static void Main(string[] args)
{
try
{
Throw();
}
catch (Exception ex)
{
throw ex;
}
}
public static void Throw()
{
int a = 0;
int b = 10 / a;
}
}
If throw; is used, the callstack is (line numbers replaced with code):
at Throw():line (int b = 10 / a;)
at Main():line (throw;) // This has been modified
If throw ex; is used, the callstack is:
at Main():line (throw ex;)
If exception is not caught, the callstack is:
at Throw():line (int b = 10 / a;)
at Main():line (Throw())
Tested in .NET 4 / VS 2010
There is a duplicate question here.
As I understand it - throw; is compiled into 'rethrow' MSIL instruction and it modifies the last frame of the stack-trace.
I would expect it to keep the original stack-trace and add the line where it has been re-thrown, but apparently there can only be one stack frame per method call.
Conclusion: avoid using throw; and wrap your exception in a new one on re-throwing - it's not ugly, it's best practice.
You can preserve stack trace using
ExceptionDispatchInfo.Capture(ex);
Here is code sample:
static void CallAndThrow()
{
throw new ApplicationException("Test app ex", new Exception("Test inner ex"));
}
static void Main(string[] args)
{
try
{
try
{
try
{
CallAndThrow();
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// rollback tran, etc
dispatchException.Throw();
}
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// other rollbacks
dispatchException.Throw();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
The output will be something like:
Test app ex
Test inner ex
at TestApp.Program.CallAndThrow() in D:\Projects\TestApp\TestApp\Program.cs:line 19
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 30
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 38
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 47
OK, there seems to be a bug in the .NET Framework, if you throw an exception, and rethrow it in the same method, the original line number is lost (it will be the last line of the method).
Fortunatelly, a clever guy named Fabrice MARGUERIE found a solution to this bug. Below is my version, which you can test in this .NET Fiddle.
private static void RethrowExceptionButPreserveStackTrace(Exception exception)
{
System.Reflection.MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
throw exception;
}
Now catch the exception as usually, but instead of throw; just call this method, and voila, the original line number will be preserved!
Not sure whether this is by design, but I think it has always been like that.
If the original throw new Exception is in a separate method, then the result for throw should have the original method name and line number and then the line number in main where the exception is re-thrown.
If you use throw ex, then the result will just be the line in main where the exception is rethrow.
In other words, throw ex loses all the stacktrace, whereas throw preserves the stack trace history (ie details of the lower level methods). But if your exception is generated by the same method as your rethrow, then you can lose some information.
NB. If you write a very simple and small test program, the Framework can sometimes optimise things and change a method to be inline code which means the results may differ from a 'real' program.
Do you want your right line number? Just use one try/catch per method. In systems, well... just in the UI layer, not in logic or data access, this is very annoying, because if you need database transactions, well, they shouldn't be in the UI layer, and you won't have the right line number, but if you don't need them, don't rethrow with nor without an exception in catch...
5 minutes sample code:
Menu File -> New Project, place three buttons, and call the following code in each one:
private void button1_Click(object sender, EventArgs e)
{
try
{
Class1.testWithoutTC();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC1();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button3_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC2();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
Now, create a new Class:
class Class1
{
public int a;
public static void testWithoutTC()
{
Class1 obj = null;
obj.a = 1;
}
public static void testWithTC1()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch
{
throw;
}
}
public static void testWithTC2()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch (Exception ex)
{
throw ex;
}
}
}
Run... the first button is beautiful!
I think this is less a case of stack trace changing and more to do with the way the line number for the stack trace is determined. Trying it out in Visual Studio 2010, the behaviour is similar to what you would expect from the MSDN documentation: "throw ex;" rebuilds the stack trace from the point of this statement, "throw;" leaves the stack trace as it as, except that where ever the exception is rethrown, the line number is the location of the rethrow and not the call the exception came through.
So with "throw;" the method call tree is left unaltered, but the line numbers may change.
I've come across this a few times, and it may be by design and just not documented fully. I can understand why they may have done this as the rethrow location is very useful to know, and if your methods are simple enough the original source would usually be obvious anyway.
As many other people have said, it usually best to not catch the exception unless you really have to, and/or you are going to deal with it at that point.
Interesting side note: Visual Studio 2010 won't even let me build the code as presented in the question as it picks up the divide by zero error at compile time.
That is because you catched the Exception from Line 12 and have rethrown it on Line 15, so the Stack Trace takes it as cash, that the Exception was thrown from there.
To better handle exceptions, you should simply use try...finally, and let the unhandled Exception bubble up.
Consider this method (pardon the sad attempt at Chuck Norris humor :) ):
public class ChuckNorrisException : Exception
{
public ChuckNorrisException()
{
}
public ChuckNorrisException(string message)
: base(message)
{
}
public ChuckNorrisException(string message, Exception cause)
: base(message, cause)
{
}
protected ChuckNorrisException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
static void ExceptionTest(double x)
{
try
{
double y = 10 / x;
Console.WriteLine("quotient = " + y);
}
catch (Exception e)
{
e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
e;
throw e;
}
}
In resharper, I get a warning on the "throw e" line saying "Exception rethrow possibly intended". But obviously in this case that's not the intention, since e could be wrapped in ChuckNorrisException, and if I just use "throw", that wrapped exception wouldn't get thrown.
I know I can suppress the resharper warning, but then it will be turned off for all scenarios if I'm not mistaken. I just wondered if anybody else had encountered this. The only workaround I've found is to make another exception variable (e2, for example), and throw that. That may be the best I can do here. Seems like resharper could detect this issue though and be smart enough to know that if e is modified, then throw e is ok.
Thanks.
[EDIT]
Sorry, I forgot a step. Before the throw, I need to log the exception, so I can't just do:
e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
e;
throw e;
I have to do:
e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
e;
LogException(e);
throw e;
Maybe I'm not understanding the question, so please correct me if I've got the wrong end of the stick.
There's two cases going on here:
The first is that you catch the
original exception. You then wrap
it in a new exception instance as
the inner exception, then throw the
new one. No information is lost in this case (the inner exception preserves all information), so no warning is given.
The second is that you catch and
re-throw the original exception. If you re-throw, you
should never use "throw e", as it
will tamper with the stack trace.
This is why ReSharper is printing a
warning. To re-throw the caught exception, you should use the "throw" keyword on its own.
The answer to this question explains it better than I can. Due to the subtle side effects and the sheer number of people who get this detail wrong, I personally view the re-throw syntax as flawed.
Anyway that's a description of why you're getting a warning. Here's what I'd do about it instead:
catch(DivideByZeroException e)
{
// we don't catch any other exceptions because we weren't
// logging them or doing anything with the exception before re-throwing
throw new ChuckNorrisException("Useful information", e);
}
*Edit -- if you need to log exceptions, you can just do something like this instead. Note: This is my preferred solution as I think it reads better and is less likely to contain an error than querying for exception types yourself:
// catch most specific exception type first
catch(DivideByZeroException e)
{
Log(e);
throw new ChuckNorrisException("Useful information", e);
}
catch(Exception e) // log & re-throw all other exceptions
{
Log(e);
throw; // notice this is *not* "throw e"; this preserves the stack trace
}
Another alternative would be:
catch(Exception e)
{
Log(e);
if(e is DivideByZeroException)
{
// wrap + throw the exception with our new exception type
throw new ChuckNorrisException("useful info", e);
}
// re-throw the original, preserving the stack trace
throw;
}
This will have the same effect as the code you have posted and should not cause the warning.
catch (DivideByZeroException de)
{
throw new ChuckNorrisException("Only Chuck Norris can divide by 0!", de);
}
}
What is the difference between
try { }
catch
{ throw; }
and
try { }
catch(Exception e)
{ throw e;}
?
And when should I use one or the other?
The constructions
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
are similar in that both will catch every exception thrown inside the try block (and, unless you are simply using this to log the exceptions, should be avoided). Now look at these:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
The first and second try-catch blocks are EXACTLY the same thing, they simply rethrow the current exception, and that exception will keep its "source" and the stack trace.
The third try-catch block is different. When it throws the exception, it will change the source and the stack trace, so that it will appear that the exception has been thrown from this method, from that very line throw e on the method containing that try-catch block.
Which one should you use? It really depends on each case.
Let's say you have a Person class with a .Save() method that will persist it into a database. Let's say that your application executes the Person.Save() method somewhere. If your DB refuses to save the Person, then .Save() will throw an exception. Should you use throw or throw e in this case? Well, it depends.
What I prefer is doing:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
This should put the DBException as the "Inner Exception" of the newer exception being throw. So when you inspect this InvalidPersonException, the stack trace will contain info back to the Save method (that might be sufficient for you to solve the problem), but you still have access to the original exception if you need it.
As a final remark, when you are expecting an exception, you should really catch that one specific exception, and not a general Exception, ie, if you are expecting an InvalidPersonException you should prefer:
try { ... }
catch (InvalidPersonException e) { ... }
to
try { ... }
catch (Exception e) { ... }
The first preserves the stack trace while the second resets it. This means that if you use the second approach the stack trace of the exception will always start from this method and you will lose the original exception trace which could be disastrous for someone reading exception logs as he will never find out the original cause of the exception.
The second approach might be useful when you want to add additional information to the stack trace but it is used like this:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
There's a blog post discussing the differences.
You should use
try { }
catch(Exception e)
{ throw }
if you want to do something with the exception before re-throwing it (logging for example). The lonely throw preserves stack trace.
The difference between a parameterless catch and a catch(Exception e) is that you get a reference to the exception. From framework version 2 unmanaged exceptions are wrapped in a managed exception, so the parameterless exception is no longer useful for anything.
The difference between throw; and throw e; is that the first one is used to rethrow exceptions and the second one is used to throw a newly created exception. If you use the second one to rethrow an exception, it will treat it like a new exception and replace all stack information from where it was originally thrown.
So, you shold not use either of the alternatives in the question. You should not use the parameterless catch, and you should use throw; to rethrow an exception.
Also, in most cases you should use a more specific exception class than the base class for all exceptions. You should only catch the exceptions that you anticipate.
try {
...
} catch (IOException e) {
...
throw;
}
If you want to add any information when rethrowing the exception, you create a new exception with the original exception as an inner exception to preservere all information:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}