空抓块

时间:2013-05-23 13:47:43

标签: c# .net exception error-handling

我有时遇到需要捕获异常的情况,如果它被抛出但从不对它做任何事情。换句话说,可能会发生异常,但如果有,则无关紧要。

我最近阅读了有关类似内容的文章:http://c2.com/cgi/wiki?EmptyCatchClause

此人谈论

的评论
// should never occur 

是代码气味,不应出现在代码中。然后他们去解释评论如何

// don't care if it happens

完全不同,我自己遇到这样的情况。例如,在发送电子邮件时,我会做类似的事情:

var addressCollection = new MailAddressCollection();
foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (Exception)
    {
        // Do nothing - if an invalid email occurs continue and try to add the rest
    }
}

现在,您可能认为这样做是个坏主意,因为您希望返回给用户并解释无法将一条或多条消息发送给收件人。但是,如果它只是一个CC地址怎么办?这不太重要,即使其中一个地址无效(可能只是一个错字),你仍然可能仍然希望发送消息。

所以我使用空挡块是对的,还是有一个我不知道的更好的替代方案?

5 个答案:

答案 0 :(得分:69)

如果在发生某种类型的异常时您真的不想做任何事情,那么使用空的catch块是完全正确的。您可以通过仅捕获您期望发生的异常类型以及您知道可以安全忽略的类型来改进您的示例。通过捕获Exception,您可以隐藏错误并使自己更难调试程序。

关于异常处理需要注意的一件事:用于表示程序外部错误情况的异常之间存在很大差异,至少有时会发生预期,以及表示编程错误的异常。第1个示例是一个异常,表示由于连接超时而无法传送电子邮件,或者由于没有磁盘空间而无法保存文件。第二个示例是一个异常,表示您尝试将错误类型的参数传递给方法,或者您尝试访问数组元素超出范围。

对于第二个(编程错误),仅仅“吞下”异常将是一个大错误。最好的做法通常是记录堆栈跟踪,然后弹出一条错误消息,告诉用户发生了内部错误,并且他们应该将他们的日志发送回开发人员(即您)。或者在开发时,您可能只是将它打印到控制台的堆栈跟踪并使程序崩溃。

对于第一个(外部问题),没有关于“正确”事情的规则。这一切都取决于应用程序的细节。如果您想忽略某个条件并继续,请执行此操作。

一般情况:

阅读技术书籍和文章是件好事。这样做你可以学到很多东西。但是请记住,正如你所读到的那样,你会发现许多人的建议是说做这样的事情总是错误或总是正确。这些意见往往与宗教有关。 从不相信以某种方式做事绝对是“正确的”,因为一本书或一篇文章(或者对SO的答案......< cough>)告诉过你。每条规则都有例外,撰写这些文章的人不知道您的申请的详细信息。你做。确保你正在阅读的内容有意义,如果没有,请相信自己。

答案 1 :(得分:18)

在正确的位置中有一个空的catch块很好 - 虽然从你的样本中我会说你应该用cetagorically NOT 使用catch (Exception)。您应该捕获您期望发生的显式异常。

这样做的原因是,如果你吞下一切,你将吞下你不期望的关键缺陷。 “我无法发送到此电子邮件地址”和“您的计算机磁盘空间不足”之间存在着天壤之别。如果磁盘空间不足,您不想继续尝试发送下一封10000封电子邮件!

“不应该发生”和“不关心它是否发生”的区别在于,如果它“不应该发生”那么,当发生时,你不想要静静地吞下它!如果这是您从未预料到的情况,您通常会希望您的应用程序崩溃(或者至少完全终止并记录发生的事情),以便您可以识别出这种不可能的情况。

答案 2 :(得分:7)

如果永远不应该抛出异常,那就没有必要抓住它 - 它永远不应该发生,如果确实如此,你需要了解它。

如果存在可能导致失败的特定情况,那么您应该捕获并测试这些特定情况并在所有其他情况下重新抛出,例如

foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (EmailNotSentException ex)
    {
        if (IsCausedByMissingCcAddress(ex))
        {
            // Handle this case here e.g. display a warning or just nothing
        }
        else
        {
            throw;
        }
    }
}

请注意,上面的代码捕获了特定的(如果是虚构的)异常,而不是捕获Exception。我可以想到很少有这样的情况:捕获Exception是合法的,而不是捕获一些你期望抛出的特定异常类型。

答案 3 :(得分:5)

许多其他答案在可以捕获异常时提供了很好的理由,但是许多类支持不抛出异常的方法。

这些方法通常会在它们前面加上前缀Try。该函数返回一个布尔值,指示任务是否成功,而不是抛出异常。

一个很好的例子是Parse vs TryParse

string s = "Potato";
int i;
if(int.TryParse(s, out i))
{
    //This code is only executed if "s" was parsed succesfully.
    aCollectionOfInts.Add(i);
}

如果你在循环中尝试上述函数并将其与Parse + Catch equilvilant进行比较,那么TryParse方法会更快。

答案 4 :(得分:2)

使用空的catch块只是吞下Exception,我总是会处理它,即使它向你报告发生了Exception

同样捕获通用Exception是不好的做法,因为它可以隐藏应用程序中的错误。例如,你可能已经发现了一个你没有意识到的ArgumentOutOfRange异常然后吞下它(即没有用它做任何事情)。