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

235,695

Solution 1

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;
         }
     }
    

Solution 2

(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?

Solution 3

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

Solution 4

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).

Solution 5

let's understand the difference between throw and throw ex. I heard that in many .net interviews this common asked is being asked.

Just to give an overview of these two terms, throw and throw ex are both used to understand where the exception has occurred. Throw ex rewrites the stack trace of exception irrespective where actually has been thrown.

Let's understand with an example.

Let's understand first Throw.

static void Main(string[] args) {
    try {
        M1();
    } catch (Exception ex) {
        Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
        Console.WriteLine(ex.StackTrace.ToString());
        Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
        Console.WriteLine(ex.TargetSite.ToString());
    }
    Console.ReadKey();
}

static void M1() {
    try {
        M2();
    } catch (Exception ex) {
        throw;
    };
}

static void M2() {
    throw new DivideByZeroException();
}

output of the above is below.

shows complete hierarchy and method name where actually the exception has thrown.. it is M2 -> M2. along with line numbers

enter image description here

Secondly.. lets understand by throw ex. Just replace throw with throw ex in M2 method catch block. as below.

enter image description here

output of throw ex code is as below..

enter image description here

You can see the difference in the output.. throw ex just ignores all the previous hierarchy and resets stack trace with line/method where throw ex is written.

Share:
235,695
dance2die
Author by

dance2die

I like to read, and build(&amp; break?) stuff. Currently helping folks out on r/reactjs &amp; DEV#react. Reach out to me @dance2die &amp; check out my blog on sung.codes

Updated on August 13, 2021

Comments

  • dance2die
    dance2die over 2 years

    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?

  • Shaul Behr
    Shaul Behr about 15 years
    This answer is incorrect! See stackoverflow.com/questions/730300/…
  • Marc Gravell
    Marc Gravell about 15 years
    @Shaul; no, it isn't. I've given details in a comment to your post.
  • Shaul Behr
    Shaul Behr about 15 years
    @Marc Gravell - my apologies, you were right. Sorry about the downvote; it's too late for me to undo... :(
  • Brann
    Brann about 13 years
    @Marc : It seems that throw preserves the original offender ONLY if the throw isn't in the method in which the initial exception was thrown (see this question : stackoverflow.com/questions/5152265/… )
  • LoganS
    LoganS almost 12 years
    @Xenan - you aren't the only one - I always get it mixed up too. It just looks strange.
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen almost 12 years
    If you modify the object referenced by ex, for example by setting the ex.HelpLink property, this is reflected with both throw; and throw ex;. If, on the other hand, you assign to the ex variable (to make it reference another object), then clearly throw; will use the original object, while throw ex; will use the new object. It is also interesting to note that even if you use the preferred throw; variant, you lose information about the line number inside the try block. I just wrote a new answer about that (see also the answer of @Shaul ).
  • Marc Gravell
    Marc Gravell almost 12 years
    @Jeppe to be fair the question clearly doesn't show a reassignment to ex
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen almost 12 years
    No, you're right. In that case throw; and throw ex; throw the same object, but its stack trace is modified in different way, as you explain in your answer.
  • Jasmine
    Jasmine about 11 years
    @Xenan: WYSIWYG - Microsoft Visual Studio editor. And even, I have just experimented throw and throw ex, as its understood by all, throw is the better option as it gives the information from the source of exception. I really wonder why you bring up things which is not necessary. What you see in the output (The real message is what we should be worrying about). I do not understand why do you bring up MSIL part and all here or how it makes sense for optimization.
  • Menahem
    Menahem over 7 years
    Its because the compiler's optimization process inlines short methods such as DevideByZero, so the stack trace IS the same. maybe you should post this as a question on it`s own
  • xr280xr
    xr280xr over 4 years
    I've just read that a benefit of exception filters is that you can avoid unwinding the stack because a catch always unwinds the stack even if you just throw; the exception. Is that different from what you are talking about here with preserving the stack trace? When I first read this a couple months ago I thought that is what you meant or they were one in the same.
  • Marc Gravell
    Marc Gravell over 4 years
    @xr280xr not what I was talking about, but an interesting question
  • xr280xr
    xr280xr over 4 years
    So it is simply the value of the StackTrace property that is not preserved but in both cases [thomaslevesque.com/2015/06/21/exception-filters-in-c-6/](th‌​e stack is unwound). Seems like a strange, and unintuitive design choice for the StackTrace. Thanks for pointing it out.
  • ruffin
    ruffin over 4 years
    @ScottDorman Looks like your link isn't being forwarded correctly after a blog migration. Looks like it now lives here. Edit: Hey, wait, that's your blog! Fix your own links! ;^D
  • Imad
    Imad over 4 years
    what could be the use case for using throw ex?
  • Marc Gravell
    Marc Gravell over 4 years
    @lmad if I ever find one, I'll let you know
  • dance2die
    dance2die over 3 years
    Very nice diagram there :)
  • Vijay Dwivedi
    Vijay Dwivedi almost 3 years
    nice explanation.