【问题标题】:The difference between try/catch/throw and try/catch(e)/throw etry/catch/throw 和 try/catch(e)/throw e 的区别
【发布时间】:2010-12-14 09:50:09
【问题描述】:

有什么区别

try { }
catch
{ throw; }

try { }
catch(Exception e)
{ throw e;}

?

我什么时候应该使用其中一种?

【问题讨论】:

    标签: c# exception-handling


    【解决方案1】:

    第一个保留堆栈跟踪,而第二个重置它。这意味着如果您使用第二种方法,异常的堆栈跟踪将始终从此方法开始,您将丢失原始异常跟踪,这对于阅读异常日志的人来说可能是灾难性的,因为他永远不会找到异常的原始原因.

    当您想向堆栈跟踪添加其他信息时,第二种方法可能很有用,但它的使用方式如下:

    try
    {
        // do something
    }
    catch (Exception ex)
    {
        throw new Exception("Additional information...", ex);
    }
    

    有一个blog post 讨论差异。

    【讨论】:

    • 嗯,知道的东西很好!
    • 那么为什么要使用第二个呢?只使用第一个更好吗?
    • 当您需要检查特定异常时,第二个会派上用场 - 想到 OutOfRangeException - 或需要记录消息等。第一个似乎是类似于 try{} 的通配符异常处理程序c++ 中的 catch(...){}。
    • David,这仅适用于 catch (Exception e) 部分。这与throwthrow e 是分开的。
    【解决方案2】:

    结构

    try { ... }
    catch () { ... } /* You can even omit the () here */
    
    try { ... }
    catch (Exception e) { ... }
    

    相似之处在于两者都会捕获try 块内抛出的每个异常(并且,除非您只是使用它来记录异常,否则应该避免 )。现在看看这些:

    try { ... }
    catch ()
    {
        /* ... */
        throw;
    }
    
    try { ... }
    catch (Exception e)
    {
        /* ... */
        throw;
    }
    
    try { ... }
    catch (Exception e)
    {
        /* ... */
        throw e;
    }
    

    第一个和第二个 try-catch 块完全相同,它们只是重新抛出当前异常,并且该异常将保留其“源”和堆栈跟踪。

    第三个 try-catch 块不同。当它抛出异常时,它将更改源和堆栈跟踪,因此看起来异常已从该方法中抛出,从包含该 try-catch 块的方法上的那一行 throw e 开始。

    你应该使用哪一个?这真的取决于每种情况。

    假设您有一个 Person 类,该类带有一个 .Save() 方法,可以将其持久化到数据库中。假设您的应用程序在某处执行Person.Save() 方法。如果您的数据库拒绝保存 Person,那么 .Save() 将抛出异常。在这种情况下,您应该使用throw 还是throw e?好吧,这取决于。

    我喜欢做的是:

    try {
        /* ... */
        person.Save();
    }
    catch(DBException e) {
        throw new InvalidPersonException(
           "The person has an invalid state and could not be saved!",
           e);
    }
    

    这应该将 DBException 作为正在抛出的新异常的“内部异常”。因此,当您检查此 InvalidPersonException 时,堆栈跟踪将包含返回到 Save 方法的信息(这可能足以让您解决问题),但如果您需要,您仍然可以访问原始异常。

    作为最后一点,当您期待一个异常时,您应该真正捕获一个特定的异常,而不是一般的Exception,即,如果您期待 InvalidPersonException,您应该更喜欢:

    try { ... }
    catch (InvalidPersonException e) { ... }
    

    try { ... }
    catch (Exception e) { ... }
    

    祝你好运!

    【讨论】:

      【解决方案3】:

      无参数 catch 和 catch(Exception e) 之间的区别在于您获得了对异常的引用。从框架版本 2 开始,非托管异常被包装在托管异常中,因此无参数异常不再适用。

      throw;throw e;的区别在于第一个用于重新抛出异常,第二个用于抛出新创建的异常。如果您使用第二个来重新抛出异常,它会将其视为新异常并替换最初抛出的所有堆栈信息。

      因此,您不应使用问题中的任何一种选择。不应该使用无参数的 catch,而应该使用throw; 重新抛出异常。

      此外,在大多数情况下,您应该为所有异常使用比基类更具体的异常类。您应该只捕获您预期的异常。

      try {
         ...
      } catch (IOException e) {
         ...
         throw;
      }
      

      如果您想在重新抛出异常时添加任何信息,您可以创建一个新异常,并将原始异常作为内部异常以保留所有信息:

      try {
         ...
      } catch (IOException e) {
         ...
         throw new ApplicationException("Some informative error message", e);
      }
      

      【讨论】:

        【解决方案4】:

        你应该使用

        try { }
        catch(Exception e)
        { throw }
        

        如果您想在重新抛出异常之前对其进行处理(例如记录)。单独的 throw 会保留堆栈跟踪。

        【讨论】:

        • 如果我将这里的“throw”替换为“throw e”会发生什么?
        猜你喜欢
        • 1970-01-01
        • 2012-06-04
        • 1970-01-01
        • 2011-04-17
        • 2018-05-30
        • 2015-07-07
        • 1970-01-01
        • 1970-01-01
        • 2014-03-18
        相关资源
        最近更新 更多