【问题标题】:What's the difference between various try-catch in C#? [duplicate]C# 中的各种 try-catch 有什么区别? [复制]
【发布时间】:2011-07-17 10:10:48
【问题描述】:

可能重复:
the difference between try/catch/throw and try/catch(e)/throw e

请原谅我的愚蠢,有人知道它们之间的区别吗?

 try
 {
      return 1 / 0;
 }
 catch (Exception)
 {
      throw;
 }

 try
 {
      return 1 / 0;
 }
 catch
 {
      throw;
 }

 try
 {
      return 1 / 0;
 }
 catch (Exception e)
 {
      throw(e);
 }

【问题讨论】:

    标签: c# try-catch


    【解决方案1】:
    1. 将仅捕获并重新抛出源自 Exception 的异常。
    2. 将捕获并重新抛出任何异常。 (编辑:从 CLRv2 开始,所有异常都源自 Exception,因此这与 1 相同。请参阅下面 Eric Lippert 的评论)。
    3. 将捕获从Exception 派生的任何异常并再次抛出它,从而重置异常的堆栈跟踪。

    【讨论】:

    • 我相信 1 & 2 是等价的,你不能抛出任何不是从 .C# 中的 Exception 派生的东西。
    • @driis:即使您不能从 C# 中抛出它们,您当然可以使用用其他语言编写的库,这些库可以并且确实 抛出其他类型的异常。如果需要,有一个机制来捕捉它们很重要。
    • @Cody:你的推理好像这是 2001 年。从 CLR v2 开始,如果抛出一个不是从 Exception 派生的对象,则会检测到该对象并将其包装在 的包装器对象中确实 派生自异常。如果您需要一些奇怪的向后兼容场景,有一些方法可以关闭该行为,但实际上,没有人需要担心不再从 Exception 派生的抛出对象。有关详细信息,请参阅 RuntimeWrappedException 的文档。
    • @Eric:你是对的!我没有的想法在 CLR 级别发生了变化。很高兴知道,我刚刚发现了 RuntimeWrappedException 类。
    【解决方案2】:

    不带参数的catch 子句可以捕获任何 类型的异常。这有时被称为“一般”catch 子句。您可能永远不应该在生产应用程序中使用它,但我想它有时可能对调试有用。它看起来像这样:

    catch
    {
    }
    

    catch 子句还可以指定要捕获的特定异常类。您应该始终在您的应用程序中执行此操作,因为您只应该捕获您知道如何处理的异常。例如,您可能想捕获DivideByZeroException;你会这样做:

    catch (DivideByZeroException)
    {
    }
    

    当然,这样做的副作用是您无法在 catch 块内引用异常类本身,因为您尚未将其分配给变量。如果您需要在捕获的异常类的实例上调用属性或方法,则需要在catch 语句中包含一个命名变量。这可能是您习惯看到的,它看起来像这样:

    catch (DivideByZeroException ex)
    {
        // do something with ex here
    }
    

    那么throw()语句有两种写法,重要的是你选择哪一种:

    1. 第一个看起来像这样:

      throw;
      

      它没有任何参数,目的是重新抛出捕获的异常,同时保留堆栈跟踪和尽可能多的有关原始异常的信息。
      (仍然存在一些边缘情况,这可能会导致您丢失堆栈跟踪,但通常这非常优于下面的替代方法。)

    2. 第二个选项将异常类的实例作为参数传递,如下所示:

      throw(ex);
      

      或者这个:

      throw ex;
      

      重新抛出指定的异常,但如上所述,它的缺点是丢失了一些堆栈跟踪信息,这些信息告诉您是哪个方法负责引发异常。您很少会使用它,除了抛出您在同一方法中创建的 new 异常对象。

      例如,如果您想捕获一个低级异常并将其包装到一个新的异常对象中以供更高级别的函数使用,您可以使用这种形式。

    【讨论】:

    • 请注意throw(ex) 等价于throw ex。就风格而言,我会使用后者(这当然只是一种意见)。
    • @svick:在风格上,我认为我同意这一点。不知道我在想什么...... :-)
    【解决方案3】:

    前两个是等价的。

    第三个通常应该避免:它从自己的堆栈帧中重新抛出异常,丢失有关进程中原始帧的信息。

    【讨论】:

      【解决方案4】:

      catch (Exception) - 捕获任何从 Exception 类派生的东西

      catch (Exception e) - 捕获任何从 Exception 类派生的东西并将其分配给变量 e,您可以使用它。

      catch - 捕捉任何抛出的东西。

      【讨论】:

        【解决方案5】:

        示例 1 和示例 2 没有区别。两者都重新抛出了原始异常,并且都捕获了一般的 Exception。如果您想捕获更具体的异常,例如DivisionByZeroException,则可以使用示例 1。

        对于最后一个示例,您没有重新抛出异常;但抛出您捕获的相同异常对象。这会导致异常堆栈跟踪被重新设置到您抛出它的位置 - 这可能是一个问题,因为堆栈跟踪不会指向代码中实际发生错误的位置。

        【讨论】:

          【解决方案6】:

          不同之处在于throw e; 将抛出具有不同堆栈跟踪的异常。见this accepted answer

          【讨论】:

            猜你喜欢
            • 2013-11-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-06
            • 2011-05-24
            • 2012-11-20
            • 2018-11-28
            相关资源
            最近更新 更多