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.
Related
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.
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've code that rethrows an exception.
When I later read the exception from task.Exception, its stacktrace points to the location where I re-threw the exception (line n and not line m, as I expected).
Why is this so? bug in TPL or more likely something I have overlooked.
As I workaround I can wrap the exception as the inner-exception in a new exception.
internal class Program
{
private static void Main(string[] args)
{
Task.Factory.StartNew(TaskMethod).ContinueWith(t => Console.WriteLine(t.Exception.InnerException));
Console.Read();
}
private static void TaskMethod()
{
try
{
line m: throw new Exception("Todo");
}
catch (Exception)
{
line n: throw;
}
}
}
Unfortunately, due to the way TPL stores exceptions until the task finished executing, the original stack trace is lost. Running your sample code in LINQPad shows that the exception was thrown at at System.Threading.Tasks.Task.Execute(), which is obviously not correct.
As a crude workaround, you could store the original stack trace (it being a simple string) on the Data property of the original exception, and you'll be able to access it then:
private static void TaskMethod()
{
try
{
throw new Exception("Todo");
}
catch (Exception ex)
{
ex.Data["OriginalStackTrace"] = ex.StackTrace;
throw;
}
}
Then you'll have the original stack trace stored in the OriginalStackTrace value of the Data dictionary:
It's not really what you want, but I hope it helps.
In the class:
private Func<T, object> pony;
In my function:
object newValue;
try {
newValue = pony.Invoke(model as T); // This is the line where I get an exception!
} catch (Exception exception) {
// This code is never run, even though I get an exception two lines up!
if(exception is DivideByZeroException) throw new DivideByZeroException("Division by zero when calculating member " + GetMemberName(), exception);
throw;
}
I expect to get exceptions when I throw them, but I get a DivideByZeroException on the line newValue = pony.Invoke(model as T);. Why is this? Can I do something about it?
This is in a asp.net mvc2-application running in Cassini at the moment.
If I select Start debugging in Visual Studio 2008, the error gets caught and rethrown with the extra information!
The problem was that I obviously haven't understood how inner exceptions work. The exception gets caught but then only the inner exception is shown, and that's a totally other issue.
Exceptions thrown from a compiled expression are handled normally by the try .. catch construct, so I'd expect that there is some other issue in your code. If you try for example the following code, it behaves as expected:
Expression<Func<int, int>> f = x => 10 / x;
Func<int, int> fcompiled = f.Compile();
try {
Console.WriteLine(fcompiled(0));
} catch (DivideByZeroException e) {
Console.WriteLine("Divison by zero");
}
As a side note, you should probably handle DivideByZeroException using a separate catch (as I did in my example). This is a cleaner and recommended way to catch different types of exceptions.
Can you check whether the exception is really unhandled when running the application without debugging (for example by adding some debug print to the catch block)? What exception is printed when you run the application (afterall, your code rethrows some exception in any case, so the output may not be clear).
The following code worked for me (this is in a C# console app, although I don't know why that would work differently from ASP.NET):
class Program
{
static void Main(string[] args)
{
var foo = new Foo<int>();
try
{
Console.WriteLine("Calling function");
foo.DoStuff(5);
}
catch(Exception ex)
{
Console.WriteLine("Caught exception: " + ex.ToString());
}
finally
{
Console.WriteLine("In finally block");
}
}
}
class Foo<T>
{
private Func<T, object> pony;
public Foo()
{
this.pony = m =>
{
throw new DivideByZeroException("Exception!");
};
}
public object DoStuff(T o)
{
return this.pony.Invoke(o);
}
}
This prints out the contents of the exception to the command line, as expected.
Well, the code executed in the compiled expression obviously generates the DivideByZeroException, right. Something tries to divide by zero in that. So what else would you expect?
Note that the debugger (especially VS) may break on exceptions, so that you should make sure to continue running the application, it should reach your catch block just fine.
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);
}