Coder Perfect

Is there any distinction between the terms “throw” and “throw ex”?

Problem

Some people have already asked what the difference is between the two. (I’m not sure why I feel compelled to bring this up…)

However, my question differs in a way that I refer to as “throw ex” in another error god-like error handling mechanism.

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 was used in the Main, I would rethrow the error with throw;. However, in the simplified code above, all errors are handled by HandleException.

When called inside HandleException, does throw ex; have the same effect as invoking throw?

Asked by dance2die

Solution #1

Yes, there is a distinction.

Answered by Marc Gravell

Solution #2

(I made a mistake earlier, and @Marc Gravell has pointed it out.)

Here’s an example of the distinction:

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 this is the result:

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

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

Keep in mind that the line number displayed in ThrowException1() and ThrowException2() refers to the throw statement, not the call to DivByZero(), which makes sense now that I think about it…

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 only in debug mode that it keeps the original stackTrace?

Answered by Shaul Behr

Solution #3

The other responses are valid, however I believe this one adds a little more detail.

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 remove the comment from the throw arithExc; line, you’ll get:

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.

You’ve very certainly forgotten where that exception occurred. This is what you get if you use the toss; line instead:

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 much better, because you can now see that the Program.Div method was the source of your troubles. However, it’s still unclear if the issue stems from line 35 or line 37 of the try block.

You lose no information if you choose the third option, wrapping in an outside exception:

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

You can see that line 35 is the one that causes the problem. However, this forces people to seek for the InnerException, and using inner exceptions in basic cases feels a little indirect.

They invoke the internal intance function InternalPreserveStackTrace() on the Exception object (via reflection) to preserve the line number (line of the try block) in this blog article. However, using reflection in this manner is not desirable (the .NET Framework might change their internal members some day without warning).

Answered by Jeppe Stig Nielsen

Solution #4

The stack trace is preserved when you throw. 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.

The stack trace is not preserved when you throw ex. As a result, all Source1 errors will be wiped out, leaving just Source2 problems to be transmitted to the client.

When reading things isn’t enough, I recommend watching this video demo of Throw vs Throw ex in C# for additional clarity.

Answered by Shivprasad Koirala

Solution #5

When you throw an exception, it becomes the “original” exception. As a result, the prior stack trace will be missing.

If you throw, the exception will just move down the line, giving you the full stack trace.

Answered by GR7

Post is based on https://stackoverflow.com/questions/730250/is-there-a-difference-between-throw-and-throw-ex