Is there a difference between "throw" and "throw ex"?

Viewed 249658

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 that I am calling "throw ex" in another error god-like handling method.

public class Program {
    public static void Main(string[] args) {
        try {
            // something
        } catch (Exception ex) {
            HandleException(ex);
        }
    }

    private static void HandleException(Exception ex) {
        if (ex is ThreadAbortException) {
            // ignore then,
            return;
        }
        if (ex is ArgumentOutOfRangeException) { 
            // Log then,
            throw ex;
        }
        if (ex is InvalidOperationException) {
            // Show message then,
            throw ex;
        }
        // and so on.
    }
}

If try & catch were used in the Main, then I would use throw; to rethrow the error. But in the above simplied code, all exceptions go through HandleException

Does throw ex; has the same effect as calling throw when called inside HandleException?

13 Answers

Yes, there is a difference.

  • throw ex resets the stack trace (so your errors would appear to originate from HandleException)

  • throw doesn't - the original offender would be preserved.

     static void Main(string[] args)
     {
         try
         {
             Method2();
         }
         catch (Exception ex)
         {
             Console.Write(ex.StackTrace.ToString());
             Console.ReadKey();
         }
     }
    
     private static void Method2()
     {
         try
         {
             Method1();
         }
         catch (Exception ex)
         {
             //throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main)
             throw ex;
         }
     }
    
     private static void Method1()
     {
         try
         {
             throw new Exception("Inside Method1");
         }
         catch (Exception)
         {
             throw;
         }
     }
    

(I posted earlier, and @Marc Gravell has corrected me)

Here's a demonstration of the difference:

static void Main(string[] args) {
    try {
        ThrowException1(); // line 19
    } catch (Exception x) {
        Console.WriteLine("Exception 1:");
        Console.WriteLine(x.StackTrace);
    }
    try {
        ThrowException2(); // line 25
    } catch (Exception x) {
        Console.WriteLine("Exception 2:");
        Console.WriteLine(x.StackTrace);
    }
}

private static void ThrowException1() {
    try {
        DivByZero(); // line 34
    } catch {
        throw; // line 36
    }
}
private static void ThrowException2() {
    try {
        DivByZero(); // line 41
    } catch (Exception ex) {
        throw ex; // line 43
    }
}

private static void DivByZero() {
    int x = 0;
    int y = 1 / x; // line 49
}

and here is the output:

Exception 1:
   at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49
   at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19

Exception 2:
   at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25

You can see that in Exception 1, the stack trace goes back to the DivByZero() method, whereas in Exception 2 it does not.

Take note, though, that the line number shown in ThrowException1() and ThrowException2() is the line number of the throw statement, not the line number of the call to DivByZero(), which probably makes sense now that I think about it a bit...

Output in Release mode

Exception 1:

at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)

Exception 2:

at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)

Is it maintains the original stackTrace in debug mode only?

Throw preserves the stack trace. So lets say Source1 throws Error1 , its caught by Source2 and Source2 says throw then Source1 Error + Source2 Error will be available in the stack trace.

Throw ex does not preserve the stack trace. So all errors of Source1 will be wiped out and only Source2 error will sent to the client.

Sometimes just reading things are not clear , would suggest to watch this video demo to get more clarity , Throw vs Throw ex in C#.

Throw vs Throw ex

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.

No, this will cause the exception to have a different stack trace. Only using a throw without any exception object in the catch handler will leave the stack trace unchanged.

You may want to return a boolean from HandleException whether the exception shall be rethrown or not.

It's better to use throw instead of throw ex.

throw ex reset the original stack trace and can't be found the previous stack trace.

If we use throw, we will get a full stack trace.

To expand on Lucero's answer, here's how you can accomplish the intent of the original code without losing the original stack trace.

public class Program {
    public static void Main(string[] args) {
        try {
            // something
        } catch (Exception ex) {
            if (!HandleException(ex)) throw;
        }
    }

    /// <returns>
    ///   true if the exception has been handled;
    ///   false if exception should be passed along
    /// </returns>
    private static bool HandleException(Exception ex) {
        if (ex is ThreadAbortException) {
            // ignore then,
            return true;
        }
        if (ex is ArgumentOutOfRangeException) { 
            // Log then,
            return false;
        }
        if (ex is InvalidOperationException) {
            // Show message then,
            return false;
        }
        // and so on.
    }
}
Related