空抓块

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

我最近阅读了这篇关于类似内容的文章: 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地址怎么办? 这不太重要,即使其中一个地址无效(可能只是一个错字),您仍然可能仍希望发送消息。

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

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

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

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

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

一般来说:

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

一个空的捕获块在正确的位置是好的 – 虽然从你的样本我会说你应该cetagorically 使用catch (Exception) 。 您应该捕获您期望发生的显式exception。

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

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

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

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

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

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

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

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

一个很好的例子是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方法会快得多。

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

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