There are some posts that asks what the difference between those two are already.
(why do I have to even mention this...)
But my question is different in a way
When you do throw ex
, that thrown exception becomes the "original" one. So all previous stack trace will not be there.
If you do throw
, the exception just goes down the line and you'll get the full stack trace.
Look at here: http://blog-mstechnology.blogspot.de/2010/06/throw-vs-throw-ex.html
Throw:
try
{
// do some operation that can fail
}
catch (Exception ex)
{
// do some local cleanup
throw;
}
It preserve the Stack information with Exception
This is called as "Rethrow"
If want to throw new exception,
throw new ApplicationException("operation failed!");
Throw Ex:
try
{
// do some operation that can fail
}
catch (Exception ex)
{
// do some local cleanup
throw ex;
}
It Won't Send Stack information with Exception
This is called as "Breaking the Stack"
If want to throw new exception,
throw new ApplicationException("operation failed!",ex);
int a = 0;
try {
int x = 4;
int y ;
try {
y = x / a;
} catch (Exception e) {
Console.WriteLine("inner ex");
//throw; // Line 1
//throw e; // Line 2
//throw new Exception("devide by 0"); // Line 3
}
} catch (Exception ex) {
Console.WriteLine(ex);
throw ex;
}
if all Line 1 ,2 and 3 are commented - Output - inner ex
if all Line 2 and 3 are commented - Output - inner ex System.DevideByZeroException: {"Attempted to divide by zero."}---------
if all Line 1 and 2 are commented - Output - inner ex System.Exception: devide by 0 ----
if all Line 1 and 3 are commented - Output - inner ex System.DevideByZeroException: {"Attempted to divide by zero."}---------
and StackTrace will be reset in case of throw ex;
The other answers are entirely correct, but this answer provides some extra detalis, I think.
Consider this example:
using System;
static class Program {
static void Main() {
try {
ThrowTest();
} catch (Exception e) {
Console.WriteLine("Your stack trace:");
Console.WriteLine(e.StackTrace);
Console.WriteLine();
if (e.InnerException == null) {
Console.WriteLine("No inner exception.");
} else {
Console.WriteLine("Stack trace of your inner exception:");
Console.WriteLine(e.InnerException.StackTrace);
}
}
}
static void ThrowTest() {
decimal a = 1m;
decimal b = 0m;
try {
Mult(a, b); // line 34
Div(a, b); // line 35
Mult(b, a); // line 36
Div(b, a); // line 37
} catch (ArithmeticException arithExc) {
Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);
// uncomment EITHER
//throw arithExc;
// OR
//throw;
// OR
//throw new Exception("We handled and wrapped your exception", arithExc);
}
}
static void Mult(decimal x, decimal y) {
decimal.Multiply(x, y);
}
static void Div(decimal x, decimal y) {
decimal.Divide(x, y);
}
}
If you uncomment the throw arithExc;
line, your output is:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 44
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
Certainly, you have lost information about where that exception happened. If instead you use the throw;
line, this is what you get:
Handling a DivideByZeroException.
Your stack trace:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 46
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
This is a lot better, because now you see that it was the Program.Div
method that caused you problems. But it's still hard to see if this problem comes from line 35 or line 37 in the try
block.
If you use the third alternative, wrapping in an outer exception, you lose no information:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 48
at Program.Main() in c:\somepath\Program.cs:line 9
Stack trace of your inner exception:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 35
In particular you can see that it's line 35 that leads to the problem. However, this requires people to search the InnerException
, and it feels somewhat indirect to use inner exceptions in simple cases.
In this blog post they preserve the line number (line of the try block) by calling (through reflection) the internal
intance method InternalPreserveStackTrace()
on the Exception
object. But it's not nice to use reflection like that (the .NET Framework might change their internal
members some day without warning).