捕捉和抛出异常;为什么这被认为是一种反模式

时间:2015-04-16 17:12:12

标签: c# exception-handling

public void DeployCourse(Course course, Client client)
{
    if (course == null) throw new ArgumentNullException("Course cannot be null");       
    if (client == null) throw new ArgumentNullException("Client cannot be null");

    try
    {
        _ftp.Transfer(client.Server.IPAddress, course.PackageUrl, course.CourseName);
    }
    catch (Exception e)
    {
        var newException = new Exception(String.Format(
            "Error deploying Course: {0} to Client: {1}. See inner exception for more details", 
            course.CourseName, client.Name), e);
        throw newException;
    }
}

我从未真正理解构成“好”异常处理的内容。一个快速的谷歌搜索显示,几乎一致,人们同意在调用堆栈深处捕获和重新抛出异常是不好的。上面,我有一些我正在写的代码的例子。这在典型的调用堆栈中非常低。我之所以这样做,是因为如果没有这段代码,很难找到无法部署的课程。我的问题是,如果我在许多(如果不是全部)方法中做了类似的事情,为异常添加更多上下文,为什么这会被视为反模式?

谢谢!

1 个答案:

答案 0 :(得分:11)

这个问题有点含糊不清,所以让我们尝试清理一下。

  

是捕获异常的模式,将其包装在另一个异常中,并将新异常抛给调用者,这是一个好的模式吗?

是的,非常好。像任何模式一样,它有利有弊。

  

有哪些优点?

当抛出的异常与调用者期望方法调用执行的操作在逻辑上相关时,它最有效。如果"操作Foo可以抛出FooFailedException"是记录合同的一部分,然后开发人员知道他们需要抓住FooFailedException并且 - 这里是关键点 - FooFailedException

如果您始终如一地应用此方法,则可以更改方法的实现详细信息,而不必担心会破坏调用方。

例如,如果您需要调用者捕获与FTP站点失败相关的异常,然后您将实现更改为还支持其他引发异常异常的协议,则调用者必须更改以及捕获新的异常(或者他们必须抓住一切)。使用此模式,无论实现细节如何,调用者都可以捕获一个例外。

这也允许调用者根据他们尝试的操作获取诊断信息,而不是根据失败的实现细节。

  

有什么缺点?

  1. 如果更改很晚,那么更改抛出的异常可能是一个重大变化。

  2. 来电者可能希望捕获更具体的潜在异常。

  3. 如果基础异常被抛出,因为您的代码有错误并且自己调用错误那么您隐藏了您的错误并将其后果传递给调用者。

  4. 有些例外情况就像"网络现在正在关闭,稍后再试#34;有些例外就像"一切都很糟糕,你真的应该关闭这个过程&# 34 ;.通过捕获所有内容并将其包装起来,您就会更难以了解异常是否可以恢复。

  5. 我们有一份受黑客入侵的证书列表;我们将列表保留在互联网上。如果证书在撤销证书列表中,我们希望不使用证书。快点,找到缺陷:

    bool revoked = false;
    try
    {
        CheckTheRevocationList(out revoked);
    }
    catch(Exception ex)
    {
        new CryptoException("revocation list could not be checked", ex);
    }
    if (!revoked) UseTheCertificate();
    
  6. 看到缺陷?那是一个安全漏洞。在999的干草堆中发现该针对该模型的正确使用对人类来说是非常困难的。 (这不是理论上的;我通过编写一个查找它的静态分析器在实际代码中找到了这个缺陷的一个版本。)

      

    我在哪里可以阅读有关异常处理模式和实践的更多信息?

    我的文章在这里:

    http://ericlippert.com/category/exception-handling/

    你应该开始的那个经常在SO上引用:

    http://ericlippert.com/2008/09/10/vexing-exceptions/