Wrong line number on stack trace - c#

I have this code
try
{
//AN EXCEPTION IS GENERATED HERE!!!
}
catch
{
SqlService.RollbackTransaction();
throw;
}
Code above is called in this code
try
{
//HERE IS CALLED THE METHOD THAT CONTAINS THE CODE ABOVE
}
catch (Exception ex)
{
HandleException(ex);
}
The exception passed as parameter to the method "HandleException" contains the line number of the "throw" line in the stack trace instead of the real line where the exception was generated. Anyone knows why this could be happening?
EDIT1
Ok, thanks to all for your answers. I changed the inner catch for
catch(Exception ex)
{
SqlService.RollbackTransaction();
throw new Exception("Enrollment error", ex);
}
Now I have the correct line on the stack trace, but I had to create a new exception. I was hoping to find a better solution :-(
EDIT2
Maybe (if you have 5 minutes) you could try this scenario in order to check if you get the same result, not very complicated to recreate.

Yes, this is a limitation in the exception handling logic. If a method contains more than one throw statement that throws an exception then you'll get the line number of the last one that threw. This example code reproduces this behavior:
using System;
class Program {
static void Main(string[] args) {
try {
Test();
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
static void Test() {
try {
throw new Exception(); // Line 15
}
catch {
throw; // Line 18
}
}
}
Output:
System.Exception: Exception of type 'System.Exception' was thrown.
at Program.Test() in ConsoleApplication1\Program.cs:line 18
at Program.Main(String[] args) in ConsoleApplication1\Program.cs:line 6
The work-around is simple, just use a helper method to run the code that might throw an exception.
Like this:
static void Test() {
try {
Test2(); // Line 15
}
catch {
throw; // Line 18
}
}
static void Test2() {
throw new Exception(); // Line 22
}
The underlying reason for this awkward behavior is that .NET exception handling is built on top of the operating system support for exceptions. Called SEH, Structured Exception Handling in Windows. Which is stack-frame based, there can only be one active exception per stack frame. A .NET method has one stack frame, regardless of the number of scope blocks inside the method. By using the helper method, you automatically get another stack frame that can track its own exception. The jitter also automatically suppresses the inlining optimization when a method contains a throw statement so there is no need to explicitly use the [MethodImpl] attribute.

"But throw; preserves the stack trace !! Use throw; "
How many times have you heard that... Well anyone who has been programming .NET for a while has almost certainly heard that and probably accepted it as the be all and end all of 'rethrowing' exceptions.
Unfortunately it's not always true. As #hans explains, if the code causing the exception occurs in the same method as the throw; statement then the stack trace gets reset to that line.
One solution is to extract the code inside the try, catch into a separate method, and another solution is to throw a new exception with the caught exception as an inner exception. A new method is slightly clumsy, and a new Exception() loses the original exception type if you attempt to catch it further up the call stack.
I found a better description of this problem was found on Fabrice Marguerie's blog.
BUT even better there's another StackOverflow question which has solutions (even if some of them involve reflection):
In C#, how can I rethrow InnerException without losing stack trace?

As of .NET Framework 4.5 you can use the ExceptionDispatchInfo class to do this without the need for another method. For example, borrowing the code from Hans' excellent answer, when you just use throw, like this:
using System;
class Program {
static void Main(string[] args) {
try {
Test();
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
static void Test() {
try {
throw new ArgumentException(); // Line 15
}
catch {
throw; // Line 18
}
}
}
It outputs this:
System.ArgumentException: Value does not fall within the expected range.
at Program.Test() in Program.cs:line 18
at Program.Main(String[] args) in Program.cs:line 6
But, you can use ExceptionDispatchInfo to capture and re-throw the exception, like this:
using System;
class Program {
static void Main(string[] args) {
try {
Test();
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
static void Test() {
try {
throw new ArgumentException(); // Line 15
}
catch(Exception ex) {
ExceptionDispatchInfo.Capture(ex).Throw(); // Line 18
}
}
}
Then it will output this:
System.ArgumentException: Value does not fall within the expected range.
at Program.Test() in Program.cs:line 15
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Program.Test() in Program.cs:line 18
at Program.Main(String[] args) in Program.cs:line 6
As you can see, ExceptionDispatchInfo.Throw appends additional information to the stack trace of the original exception, adding the fact that it was re-thrown, but it retains the original line number and exception type. See the MSDN documentation for more information.

Does the date/time stamp of your .pdb file match your .exe/.dll file? If not, it could be that the compilation is not in "debug mode" which generates a fresh .pdb file on each build. The pdb file has the accurate line numbers when exceptions occur.
Look into your compile settings to make sure the debug data is generated, or if you're in a test/production environment, check the .pdb file to make sure the timestamps match.

C# stack traces are generated at throw time, not at exception creation time.
This is different from Java, where the stack traces are filled at exception creation time.
This is apparently by design.

I often get this in production systems if Optimize code is checked.
This screws up line numbers even in 2016.
Make sure your configuration is set to 'Release' or whatever configuration you are building and deploying under. The checkbox has a different value per configuration
I never ultimately know how more 'optimized' my code is with this checked - so check it back if you need to - but it has saved my stack trace on many occasions.

Related

Why do "throw" and "throw ex" have the same behavior in this case?

I'm flabbergasted. I always thought that throw by itself in a catch block would throw the exception at hand without altering the stack trace, but that throw ex in a catch block would alter the stack trace to show the exception originating at the location of the statement.
Take the following two blocks of code. I would expect the output to be subtly different because one uses throw and the other uses throw ex, but the output is identical between the two, and the actual source line that incited the initial exception is lost in both cases, which seems terrible to me. What am I missing?
This first example behaves as I would expect:
using System;
public class Program
{
public static void Main()
{
try
{
DummyWork();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void DummyWork()
{
try
{
throw new Exception("dummy");
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw ex; // I would expect to lose the information about the inciting line 5 above this one in this case.... and I do.
}
}
}
This second example behaves identical to the first, but I DO NOT expect that:
using System;
public class Program
{
public static void Main()
{
try
{
DummyWork();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void DummyWork()
{
try
{
throw new Exception("dummy");
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw; // I would NOT expect to lose the information about the inciting line 5 above this one in this case.... But I do. Output is identical.
}
}
}
UPDATE:
Some commenters have said they can't repro this - here is my dot fiddle (you will have to manually edit it to go back and forth between the two versions): https://dotnetfiddle.net/Mj7eK5
UPDATE #2: In answer to some commenters who have asked for the "identical" output. Here is the output from the first example:
System.Exception: dummy
at Program.DummyWork() in d:\Windows\Temp\xoyupngb.0.cs:line 21
System.Exception: dummy
at Program.DummyWork() in d:\Windows\Temp\xoyupngb.0.cs:line 26
at Program.Main() in d:\Windows\Temp\xoyupngb.0.cs:line 9
And here is the output from the second example:
System.Exception: dummy
at Program.DummyWork() in d:\Windows\Temp\jy4xgqrf.0.cs:line 21
System.Exception: dummy
at Program.DummyWork() in d:\Windows\Temp\jy4xgqrf.0.cs:line 26
at Program.Main() in d:\Windows\Temp\jy4xgqrf.0.cs:line 9
Leaving aside the insignificant temp file differences, in both cases the outer catch (the second one) is missing the line 21 of the initial throw. I would expect that in the first example throw ex but not in the second throw.
Note: This answer is for .NET Framework. You might observe a different behavior if you're using .NET Core or .NET 5.0 and above, as mentioned in the comments. I did not test on all versions of .NET Core
Okay, let me take a stab at it. The difference between throw and throw ex is already explained in Is there a difference between "throw" and "throw ex"? but I'll try to put it in more clear terms to fit the narrative of this question.
throw ex: Rethrows the exception from this point and resets the stack trace.
throw: Rethrows the exception from this point and preserves the stack trace.
Let's look at the code in question:
private static void DummyWork()
{
try
{
throw new Exception("dummy"); // Line 21
}
catch (Exception ex)
{
throw; // Line 25
}
}
Here, whether we use throw or throw ex, the stack trace will always be:
at Program.DummyWork() in ...:line 25
at Program.Main() in ...:line 9
Q: Why "line 25"?
A: Because both throw and throw ex rethrow the exception from that point.
Q: Why is there no difference in this case?
A: Because there aren't any more stack frames in the stack trace to reset.
Q: How can we see the difference?
Well, let's add another level to generate another stack frame. The code would be something like this:
private static void DummyWork()
{
try
{
MoreDummyWork(); // Line 21
}
catch (Exception ex)
{
throw; //Line 25
}
}
private static void MoreDummyWork()
{
throw new Exception("dummy"); // Line 31
}
Here, we can clearly see the difference. If we use throw, the stack trace is the following:
at Program.MoreDummyWork() in ...:line 31
at Program.DummyWork() in ...:line 25
at Program.Main() in ...:line 9
But if we use throw ex, the stack trace becomes:
at Program.DummyWork() in ...:line 25
at Program.Main() in ...:line 9
Q: Okay, you say both will throw the exception from that point. What if I want to maintain the original line number?
A: In this case, you can use ExceptionDispatchInfo.Capture(ex).Throw(); as explained in How to rethrow InnerException without losing stack trace in C#?:

Throwing an exception more than once loses its original stack trace

I have been playing around with Exceptions to learn more about how I should use them properly. So far, I know that throw keeps the original stack trace; throw new CustomException(...) is generally used when wanting to add more information about the exception that took place or add/change the message, or even change the type of Exception itself; and throw ex should never ever be used, unless I want to lose the original stack trace.
So I wrote a small program where I could catch and rethrow an exception several times while adding something to the original message.
public class Sample
{
static void Main(string[] args)
{
new Tester().FirstCall();
}
}
public class Tester
{
public void FirstCall()
{
try
{
SecondCall();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
Console.WriteLine(e.Message);
}
}
public void SecondCall()
{
try
{
ThirdCall();
}
catch (GoodException ex)
{
throw new Exception(ex.Message, ex);
}
}
public void ThirdCall()
{
try
{
FourthCall();
}
catch (ArithmeticException ae)
{
throw new GoodException("Arithmetic mistake: " + ae.Message, ae);
}
}
public void FourthCall()
{
int d = 0;
int x = 10 / d;
}
}
Where GoodException is a custom exception implemented correctly.
I'm expecting the console to display something like this:
at PlayingWithExceptions.Tester.FourthCall() in d:\Projects\PlayingWithExceptions\PlayingWithExceptions\Trying.cs:line 67
at PlayingWithExceptions.Tester.ThirdCall() in d:\Projects\PlayingWithExceptions\PlayingWithExceptions\Trying.cs:line 59
at PlayingWithExceptions.Tester.SecondCall() in d:\Projects\PlayingWithExceptions\PlayingWithExceptions\Trying.cs:line 41
at PlayingWithExceptions.Tester.FirstCall() in d:\Projects\PlayingWithExceptions\PlayingWithExceptions\Trying.cs:line 25
Arithmetic mistake: Attempted to divide by zero.
But instead I'm getting this:
at PlayingWithExceptions.Tester.SecondCall() in d:\Projects\PlayingWithExceptions\PlayingWithExceptions\Trying.cs:line 41
at PlayingWithExceptions.Tester.FirstCall() in d:\Projects\PlayingWithExceptions\PlayingWithExceptions\Trying.cs:line 25
Arithmetic mistake: Attempted to divide by zero.
For some reason it only goes as far as the second call. Even though I'm passing the caught exception as an InnerException, the stack trace is still lost. I'm aware that if I just wrote throw instead of throwing a new exception, I could keep the original stack trace, but if I do that I won't be able to change the original message (which was the whole point of this exercise).
So my question is, what can I do to change the Exception message AND keep the original stack trace the whole way?
EDIT: Since an exception should not be used logic control and only caught once, the proper way to keep the original stack trace AND show the new message is to wrap the FourthCall in a try/catch (where the new Exception with its message is generated), and catch it only once all the way up in the FirstCall.
The stack trace isn't "lost" it's pushed into the InnerException, just like you told it to be. The "outer" exception in this case, did not participate in the call chain of the Inner exception - it's a brand new exception which originates in SecondCall, so that's the beginning of its stack trace.
And yes, the commenters are correct. To control your messaging, you won't do that by trying to set the message in the Exception object - Exceptions should be handled by code, messages are for users. So, you'll log the message, display it to the user, something like that.
Don't know if it still relevant for you. Just use the keyword "throw" without the exception append to it , then the trace will not be lost and the original exception will be throws. not as inner.

What is the throw keyword responsible for in a C# error handling exercise

I am trying to learn how to debug and handle errors in C# code using VS2012 for Desktop. I am stepping-through the below code using the Step Into F11 technique.
I understand how the execution of code jumps between different parts of code. I have messages printed out to console to help me identify which step is being executed. I have split my screen so I can see which line of code I'm stepping into and the output messages in the console at the same time.
On line 70 (marked in the comments) - when the nested index is passed to the throwException() I do not understand why there is a throw keyword and what its functionality is. Why does the pointer jump to the nested finally block but then it goes back all the way to the main and throws IndexOutOfBounds exception. What does that mean? I see where the execution jump in the code but I don't understand why it just says throw. Does it mean that the exception is already handled? But how?
I read that when you throw an exception there is no need to add a break; statement because the switch statement breaks when it meets throw keyword, but I am not sure this is the right path of thinking in this example.
Please, help me understand the meaning of the throw keyword on line 70.
Thank you in advance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ch07Ex02
{
class Program
{
static string[] eTypes = { "none", "simple", "index", "nested index" };
static void Main(string[] args)
{
foreach (string eType in eTypes)
{
try
{
Console.WriteLine("Main() try block reached."); // Line 19
Console.WriteLine("ThrowException(\"{0}\") called.", eType);
ThrowException(eType);
Console.WriteLine("Main() try block continues."); // Line 22
}
catch (System.IndexOutOfRangeException e) // Line 24
{
Console.WriteLine("Main() System.IndexOutOfRangeException catch"
+ " block reached. Message:\n\"{0}\"",
e.Message);
}
catch // Line 30
{
Console.WriteLine("Main() general catch block reached.");
}
finally
{
Console.WriteLine("Main() finally block reached.");
}
Console.WriteLine();
}
Console.ReadKey();
}
static void ThrowException(string exceptionType)
{
Console.WriteLine("ThrowException(\"{0}\") reached.", exceptionType);
switch (exceptionType)
{
case "none":
Console.WriteLine("Not throwing an exception.");
break; // Line 50
case "simple":
Console.WriteLine("Throwing System.Exception.");
throw new System.Exception(); // Line 53
case "index":
Console.WriteLine("Throwing System.IndexOutOfRangeException.");
eTypes[4] = "error"; // Line 56
break;
case "nested index":
try // Line 59
{
Console.WriteLine("ThrowException(\"nested index\") " +
"try block reached.");
Console.WriteLine("ThrowException(\"index\") called.");
ThrowException("index"); // Line 64
}
catch // Line 66
{
Console.WriteLine("ThrowException(\"nested index\") general"
+ " catch block reached.");
throw; // Line 70
}
finally
{
Console.WriteLine("ThrowException(\"nested index\") finally"
+ " block reached.");
}
break;
}
}
}
}
The above code compiles and runs with no errors.
Keyword throw can be used all by itself inside a catch clause to rethrow whatever exception has been caught by that catch block. It lets you "plug in" some execution logic in the process of handling the exception without disrupting the details of where the exception has been thrown.
In this case, you are able to log the details to console, and then re-throw the exception as if you never handled it. Note that this is different from catching an exception and wrapping it in your own, because the details of the original exception are preserved.
throw; inside a catch says "I don't actually know what to do about this exception so let somebody else higher up the stack catch it (without me having modified it)."
The throw in question will re-throw the exception, such that the stack trace and other info is preserved.
Have a look at Rethrow to preserve stack details
Also from try-catch (C# Reference)
If you want to re-throw the exception currently handled by a
parameter-less catch clause, use the throw statement without arguments
catch
{
throw;
}
The throw keyword is used to re-throw caught exceptions without losing the correct stack trace. It is used to do some execution when the exception is caught (for example logging, as it is in your example).
Please see this: SO qeustion on rethrowing exceptions
and this: codinghorror blogpost (please note the clarifications in the comments)

Difference between 'throw' and 'throw new Exception()'

What is the difference between
try { ... }
catch{ throw }
and
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
regardless that the second shows a message.
throw; rethrows the original exception and preserves its original stack trace.
throw ex; throws the original exception but resets the stack trace, destroying all stack trace information until your catch block.
NEVER write throw ex;
throw new Exception(ex.Message); is even worse. It creates a brand new Exception instance, losing the original stack trace of the exception, as well as its type. (eg, IOException).
In addition, some exceptions hold additional information (eg, ArgumentException.ParamName).
throw new Exception(ex.Message); will destroy this information too.
In certain cases, you may want to wrap all exceptions in a custom exception object, so that you can provide additional information about what the code was doing when the exception was thrown.
To do this, define a new class that inherits Exception, add all four exception constructors, and optionally an additional constructor that takes an InnerException as well as additional information, and throw your new exception class, passing ex as the InnerException parameter. By passing the original InnerException, you preserve all of the original exception's properties, including the stack trace.
The first preserves the original stacktrace:
try { ... }
catch
{
// Do something.
throw;
}
The second allows you to change the type of the exception and/or the message and other data:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
There's also a third way where you pass an inner exception:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
I'd recommend using:
the first if you want to do some cleanup in error situation without destroying information or adding information about the error.
the third if you want to add more information about the error.
the second if you want to hide information (from untrusted users).
One other point that I didn't see anyone make:
If you don't do anything in your catch {} block, having a try...catch is pointless. I see this all the time:
try
{
//Code here
}
catch
{
throw;
}
Or worse:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
Worst yet:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
Throwing a new Exception blows away the current stack trace.
throw; will retain the original stack trace and is almost always more useful. The exception to that rule is when you want to wrap the Exception in a custom Exception of your own. You should then do:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
None of the answers here show the difference, which could be helpful for folks struggling to understand the difference. Consider this sample code:
using System;
using System.Collections.Generic;
namespace ExceptionDemo
{
class Program
{
static void Main(string[] args)
{
void fail()
{
(null as string).Trim();
}
void bareThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw;
}
}
void rethrow()
{
try
{
fail();
}
catch (Exception e)
{
throw e;
}
}
void innerThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw new Exception("outer", e);
}
}
var cases = new Dictionary<string, Action>()
{
{ "Bare Throw:", bareThrow },
{ "Rethrow", rethrow },
{ "Inner Throw", innerThrow }
};
foreach (var c in cases)
{
Console.WriteLine(c.Key);
Console.WriteLine(new string('-', 40));
try
{
c.Value();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
Which generates the following output:
Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
--- End of inner exception stack trace ---
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
The bare throw, as indicated in the previous answers, clearly shows both the original line of code that failed (line 12) as well as the two other points active in the call stack when the exception occurred (lines 19 and 64).
The output of the rethrow case shows why it's a problem. When the exception is rethrown like this the exception won't include the original stack information. Note that only the throw e (line 35) and outermost call stack point (line 64) are included. It would be difficult to track down the fail() method as the source of the problem if you throw exceptions this way.
The last case (innerThrow) is most elaborate and includes more information than either of the above. Since we're instantiating a new exception we get the chance to add contextual information (the "outer" message, here but we can also add to the .Data dictionary on the new exception) as well as preserving all of the information in the original exception (including help links, data dictionary, etc.).
throw rethrows the caught exception, retaining the stack trace, while throw new Exception loses some of the details of the caught exception.
You would normally use throw by itself to log an exception without fully handling it at that point.
BlackWasp has a good article sufficiently titled Throwing Exceptions in C#.
throw is for rethrowing a caught exception. This can be useful if you want to do something with the exception before passing it up the call chain.
Using throw without any arguments preserves the call stack for debugging purposes.
Your second example will reset the exception's stack trace. The first most accurately preserves the origins of the exception.
Also you've unwrapped the original type which is key in knowing what actually went wrong... If the second is required for functionality - e.g., to add extended information or rewrap with a special type such as a custom 'HandleableException' then just be sure that the InnerException property is set too!
Throw;: Rethrow the original exception and keep the exception type.
Throw new exception();: Rethrow the original exception type and reset the exception stack trace
Throw ex;: Reset the exception stack trace and reset the exception type
If you want you can throw a new Exception, with the original one set as an inner exception.
Most important difference is that the second expression erases the type of the exception. And the exception type plays a vital role in catching exceptions:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
If foo() throws an IOException, the [1] catch block will catch the exception. But when bar() throws IOException, it will be converted to plain Exception and won't be caught by the [1] catch block.
throw or throw ex, both are used to throw or rethrow the exception, when you just simply log the error information and don't want to send any information back to the caller you simply log the error in catch and leave.
But in case you want to send some meaningful information about the exception to the caller you use throw or throw ex. Now the difference between throw and throw ex is that throw preserves the stack trace and other information, but throw ex creates a new exception object and hence the original stack trace is lost.
So when should we use throw and throw e? There are still a few situations in which you might want to rethrow an exception like to reset the call stack information.
For example, if the method is in a library and you want to hide the details of the library from the calling code, you don’t necessarily want the call stack to include information about private methods within the library. In that case, you could catch exceptions in the library’s public methods and then rethrow them so that the call stack begins at those public methods.

Best practices for catching and re-throwing .NET exceptions

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.

Categories

Resources