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

前端 未结 10 2356
夕颜
夕颜 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:27

    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;
          }
      }
      
    0 讨论(0)
  • 2020-11-22 01:27

    Microsoft Docs stands for:

    Once an exception is thrown, part of the information it carries is the stack trace. The stack trace is a list of the method call hierarchy that starts with the method that throws the exception and ends with the method that catches the exception. If an exception is re-thrown by specifying the exception in the throw statement, the stack trace is restarted at the current method and the list of method calls between the original method that threw the exception and the current method is lost. To keep the original stack trace information with the exception, use the throw statement without specifying the exception.

    Source: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2200

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

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

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

    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.

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

    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.

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

    To give you a different perspective on this, using throw is particularly useful if you're providing an API to a client and you want to provide verbose stack trace information for your internal library. By using throw here, I'd get the stack trace in this case of the System.IO.File library for File.Delete. If I use throw ex, then that information will not be passed to my handler.

    static void Main(string[] args) {            
       Method1();            
    }
    
    static void Method1() {
        try {
            Method2();
        } catch (Exception ex) {
            Console.WriteLine("Exception in Method1");             
        }
    }
    
    static void Method2() {
        try {
            Method3();
        } catch (Exception ex) {
            Console.WriteLine("Exception in Method2");
            Console.WriteLine(ex.TargetSite);
            Console.WriteLine(ex.StackTrace);
            Console.WriteLine(ex.GetType().ToString());
        }
    }
    
    static void Method3() {
        Method4();
    }
    
    static void Method4() {
        try {
            System.IO.File.Delete("");
        } catch (Exception ex) {
            // Displays entire stack trace into the .NET 
            // or custom library to Method2() where exception handled
            // If you want to be able to get the most verbose stack trace
            // into the internals of the library you're calling
            throw;                
            // throw ex;
            // Display the stack trace from Method4() to Method2() where exception handled
        }
    }
    
    0 讨论(0)
提交回复
热议问题