Is there a difference between “throw” and “throw ex”?

前端 未结 10 2357
夕颜
夕颜 2020-11-22 01:08

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

相关标签:
10条回答
  • 2020-11-22 01:42

    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.

    0 讨论(0)
  • 2020-11-22 01:48

    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);
    
    0 讨论(0)
  • 2020-11-22 01:48
    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;
    }
    
    1. if all Line 1 ,2 and 3 are commented - Output - inner ex

    2. if all Line 2 and 3 are commented - Output - inner ex System.DevideByZeroException: {"Attempted to divide by zero."}---------

    3. if all Line 1 and 2 are commented - Output - inner ex System.Exception: devide by 0 ----

    4. 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;

    0 讨论(0)
  • 2020-11-22 01:50

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

    0 讨论(0)
提交回复
热议问题