“扔”和“扔前”有区别吗?

有一些帖子询问这两者之间的区别是什么。
(为什么我不得不提到这一点...)

但是我的问题不同于我在另一个错误神般的处理方法中称之为“抛出”的方式。

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

如果在Main中使用try & catch ,那么我会使用throw; 重新抛出错误。 但是在上面简单的代码中,所有的异常都经过HandleException

throw ex;HandleException调用throw时有同样的效果吗?


是,有一点不同;

  • throw ex重置堆栈跟踪(所以你的错误似乎源于HandleException
  • throw没有 - 原始的罪犯将被保留。

  • (我之前发布了,@Marc Gravell纠正了我)

    以下是差异的演示:

            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
        }
    

    这里是输出:

    Exception 1:
       at UnitTester.Program.DivByZero() in <snip>DevUnitTesterProgram.cs:line 49
       at UnitTester.Program.ThrowException1() in <snip>DevUnitTesterProgram.cs:line 36
       at UnitTester.Program.TestExceptions() in <snip>DevUnitTesterProgram.cs:line 19
    
    Exception 2:
       at UnitTester.Program.ThrowException2() in <snip>DevUnitTesterProgram.cs:line 43
       at UnitTester.Program.TestExceptions() in <snip>DevUnitTesterProgram.cs:line 25
    

    您可以看到,在例外1中,堆栈跟踪会返回到DivByZero()方法,而在例外2中则不会。

    但请注意, ThrowException1()ThrowException2()中显示的行号是throw语句的行号, 而不是调用DivByZero()的行号,现在我认为它可能是有意义的位...

    在释放模式下输出

    例外1:

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

    例外2:

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

    是否仅在调试模式下维护原始堆栈跟踪?


    其他答案完全正确,但我认为这个答案提供了一些额外的问题。

    考虑这个例子:

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

    如果你取消注释throw arithExc; 行,你的输出是:

    Handling a DivideByZeroException.
    Your stack trace:
       at Program.ThrowTest() in c:somepathProgram.cs:line 44
       at Program.Main() in c:somepathProgram.cs:line 9
    
    No inner exception.
    

    当然,你已经失去了有关异常发生的信息。 如果你使用throw; 线,这是你得到的:

    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:somepathProgram.cs:line 58
       at Program.ThrowTest() in c:somepathProgram.cs:line 46
       at Program.Main() in c:somepathProgram.cs:line 9
    
    No inner exception.
    

    这样会好很多,因为现在你发现它是Program.Div方法导致了你的问题。 但是仍然很难看到这个问题来自try块中的第35行还是第37行。

    如果您使用第三种替代方法,则封装在外部异常中,则不会丢失任何信息:

    Handling a DivideByZeroException.
    Your stack trace:
       at Program.ThrowTest() in c:somepathProgram.cs:line 48
       at Program.Main() in c:somepathProgram.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:somepathProgram.cs:line 58
       at Program.ThrowTest() in c:somepathProgram.cs:line 35
    

    特别是你可以看到它是导致这个问题的第35行 。 但是,这需要人们搜索InnerException ,并且在简单情况下使用内部异常感觉有点间接。

    在此博客文章中,他们通过调用(通过反射) Exception对象的internal实例方法InternalPreserveStackTrace()来保留行号(try块的行)。 但是使用这样的反射并不好(.NET框架有可能会在没有警告的情况下改变它们的internal成员)。

    链接地址: http://www.djcxy.com/p/34931.html

    上一篇: Is there a difference between "throw" and "throw ex"?

    下一篇: When to throw an exception?