Example of chained exceptions stack - c#

I do not know much about these technologies, and was not very successful at finding how an exception stack is displayed.
Therefore, several basic questions:
how are 2 independent successive exceptions shown?
how are several chained exceptions displayed?
is the root cause displayed at the top or the bottom of the stack?

It's pretty easy to try this for yourself. For example:
using System;
class Test
{
static void Main(string[] args)
{
try
{
Top();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
static void Top()
{
try
{
Middle();
}
catch (Exception e)
{
throw new Exception("Exception from top", e);
}
}
static void Middle()
{
try
{
Bottom();
}
catch (Exception e)
{
throw new Exception("Exception from middle", e);
}
}
static void Bottom()
{
throw new Exception("Exception from bottom");
}
}
Results (the first two lines would be on one line if it were long enough):
System.Exception: Exception from top ---> System.Exception: Exception from middle
---> System.Exception: Exception from bottom
at Test.Bottom() in c:\Users\Jon\Test\Test.cs:line 43
at Test.Middle() in c:\Users\Jon\Test\Test.cs:line 33
--- End of inner exception stack trace ---
at Test.Middle() in c:\Users\Jon\Test\Test.cs:line 37
at Test.Top() in c:\Users\Jon\Test\Test.cs:line 21
--- End of inner exception stack trace ---
at Test.Top() in c:\Users\Jon\Test\Test.cs:line 25
at Test.Main(String[] args) in c:\Users\Jon\Test\Test.cs:line 9

When two independent successive exceptions are thrown, the first one will interrupt the normal execution of the program, until it is handled. Then, the second exception will be thrown in the same way, if the program was not terminated by the first one.
As for chained exceptions, you will see the last thrown exception, but that last exception was thrown when handling another exception and so forth. For example:
void Foo()
{
throw new FooException("foo");
}
void Bar()
{
try
{
Foo();
}
catch(FooException ex)
{
throw new BarException("bar", /* innerException = */ ex);
}
}
So at the top of the stack you will see BarException and at the bottom, the FooException. Hope I did not miss anything.

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#?:

C# - Create new exception without losing stack trace and inner exceptions?

I have a method that provides an Exception object and I want to log an error if anything happens in the error handler itself. Here is some pseudocode:
public override void OnError(Exception originalException)
{
try
{
// Do work...
}
catch (Exception e)
{
// How do I create this exception without losing the stack
// trace of e and preserving any inner exceptions that were
// in e at the same time including the details of
// originalException?
Exception newException = new Exception(e.Message, originalException);
Logger.Error("An error occurred", newException);
}
}
Basically, I am trying to combine originalException and e above into one Exception message to pass to a logger object. I suppose one option would be to create 2 separate log messages but it's not ideal.
You could use an AggregateException to wrap multiple exceptions:
public override void OnError(Exception originalException)
{
try
{
// Do work...
}
catch (Exception e)
{
var exs = new AggregateException(originalException, e);
Logger.Error("An error occurred", exs);
}
}
EDIT: If Logger doesn't record contents of the InnerException property (or InnerExceptions in this case) then seems the only option is multiple calls to Logger.Error.

Why do "throw" and "throw ex" in a catch block behave the same way?

I read that when in a catch block, I can rethrow the current exception using "throw;" or "throw ex;".
From: http://msdn.microsoft.com/en-us/library/ms182363%28VS.80%29.aspx
"To keep the original stack trace information with the exception, use the throw statement without specifying the exception."
But when I try this with
try{
try{
try{
throw new Exception("test"); // 13
}catch (Exception ex1){
Console.WriteLine(ex1.ToString());
throw; // 16
}
}catch (Exception ex2){
Console.WriteLine(ex2.ToString()); // expected same stack trace
throw ex2; // 20
}
}catch (Exception ex3){
Console.WriteLine(ex3.ToString());
}
I get three different stacks. I was expecting the first and second trace to be the same. What am I doing wrong? (or understanding wrong?)
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in c:\Program.cs:line 13
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in c:\Program.cs:line 16
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in c:\Program.cs:line 20
throw will only preserve the stack frame if you don't throw it from within the current one. You're doing just that by doing all of this in one method.
See this answer: https://stackoverflow.com/a/5154318/1517578
PS: +1 for asking a question that was actually a valid question.
Simon beat me to answering, but you can see the expected behaviour simply by throwing the original exception from inside another function:
static void Main(string[] args)
{
try
{
try
{
try
{
Foo();
}
catch (Exception ex1)
{
Console.WriteLine(ex1.ToString());
throw;
}
}
catch (Exception ex2)
{
Console.WriteLine(ex2.ToString()); // expected same stack trace
throw ex2;
}
}
catch (Exception ex3)
{
Console.WriteLine(ex3.ToString());
}
}
static void Foo()
{
throw new Exception("Test2");
}
Well I dug a bit more on this issue and here is my very personal conclusion:
Never use “throw;” but always rethrow a new Exception with the
cause specified.
Here is my reasoning:
I was influenced by my previous experience with Java and expected C# throw to be very similar to that of Java. Well I dug a bit more on this issue and here are my observations:
static void Main(string[] args){
try {
try {
throw new Exception("test"); // 13
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw ex;// 17
}
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
Yields:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17
Intuitively, a Java programmer would have expected both exceptions to be the same:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
But the C# documentation clearly says that this is what is to be expected:
“If an exception is re-thrown by specifying the exception in the throw statement, the stack trace is restarted at the current method and the list of method calls between the original method that threw the exception and the current method is lost. To keep the original stack trace information with the exception, use the throw statement without specifying the exception.”
Now if I slightly changed the test (replacing throw ex; by throw; on line 17).
try {
try {
throw new Exception("test"); // 13
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw;// 17
}
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Yields:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17
Obviously this is not what I expected (as this was the original question). I lost the original throw point in the second stack trace. Simon Whitehead linked the explanation, which is that throw; preserves the stack trace only if the exception did not occur in the current method. So “throw” without parameter in the same method is pretty useless as, in general, it will not help you find the cause of the exception.
Doing what any Java programmer would do, I replaced the statement on line 17 by:
throw new Exception("rethrow", ex);// 17
Yields:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
System.Exception: rethrow ---> System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
--- End of inner exception stack trace ---
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17
which is a much better result.
Then, I started testing with method calls.
private static void throwIt() {
throw new Exception("Test"); // 10
}
private static void rethrow(){
try{
throwIt(); // 15
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw; // 18
}
}
static void Main(string[] args){
try{
rethrow(); // 24
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
Again, the stack traces were not what I (a Java programmer) expected. In Java, both stacks would have been the same and three method deep as:
java.lang.Exception: Test
at com.example.Test.throwIt(Test.java:10)
at com.example.Test.rethrow(Test.java:15)
at com.example.Test.main(Test.java:24)
The first stack trace is only two method deep.
System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow() in Program.cs:line 15
It is like if the stack trace was being populated as part of the stack unwinding process. If I was to log the stack trace to investigate the exception at that point, I’d probably be missing vital information.
The second stack trace is three method deep but line 18 (throw;) appears in it.
System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow() in Program.cs:line 18
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 24
This observation is similar to the one made earlier: the stack trace is not preserved for the current method scope and again I loose the called method in which the exception occurs. For example, if rethow was written as:
private static void rethrow(){
try{
if (test)
throwIt(); // 15
else
throwIt(); // 17
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw; // 20
}
}
Yields
System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow() in Program.cs:line 20
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 26
Which call to throwIt() threw the Exception? Stack says line 20 so is it line 15 or 17?
The solution is the same as the previous: wrap the cause in a new exception which yields:
System.Exception: rethrow ---> System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow(Boolean test) in Program.cs:line 17
--- End of inner exception stack trace ---
at ConsoleApplication1.Program.rethrow(Boolean test) in Program.cs:line 20
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 26
My simple conclusion to all this is to never use “throw;” but to always rethrow a new exception with the cause specified.

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