抓住一个普遍的例外真的那么糟糕吗?

时间:2020-03-05 18:41:55  来源:igfitidea点击:

在使用FXCop分析一些旧代码时,我想到的是,在try块中捕获一般异常错误确实很不好,或者我们是否正在寻找特定的异常。请在明信片上提出想法。

解决方案

回答

好吧,我没有发现捕获一般异常或者特定异常之间的任何区别,除了在拥有多个catch块时,我们可以根据异常是什么做出不同的反应。

我们将使用通用的Exception捕获IOException和NullPointerException,但是程序应采取的反应方式可能有所不同。

回答

我认为一个好的指导方针是仅捕获框架内的特定异常(以便主机应用程序可以处理磁盘填充等边缘情况),但是我不明白为什么我们不应该捕获所有异常应用程序代码中的异常。有时候,无论发生什么问题,我们都不希望应用程序崩溃。

回答

在大多数情况下,不需要捕获一般性异常。当然,有些情况下我们别无选择,但是在这种情况下,我认为最好检查一下为什么需要抓住它。也许设计有问题。

回答

除非我们在应用程序的前端进行一些日志记录和清理代码,否则我认为捕获所有异常是不好的。

我的基本经验法则是捕获我们期望的所有异常,而其他任何东西都是错误。

如果我们抓住了所有东西并继续操作,那有点像在汽车仪表板上的警告灯上贴上膏药。我们再也看不到它,但这并不意味着一切都很好。

回答

我认为这是双重的。

首先,如果我们不知道发生了什么异常,我们如何希望从异常中恢复过来。如果我们希望用户输入错误的文件名,那么可以期待FileNotFoundException并告诉用户重试。如果相同的代码生成了NullReferenceException,而我们只是告诉用户重试,他们将不知道发生了什么。

其次,FxCop指南确实将重点放在库/框架代码上,但并非所有规则都旨在适用于EXE或者ASP.Net网站。因此,拥有一个将记录所有异常并很好地退出应用程序的全局异常处理程序是一件好事。

回答

显然,这是唯一的真实答案是"取决于"的问题之一。

它主要取决于我们在哪里捕获异常。通常,库在捕获异常时应该更加保守,而在程序的顶层(例如,在主方法中或者在控制器的action方法的顶部等)中,我们可以对捕获的内容更加自由。

其原因是例如我们不希望捕获库中的所有异常,因为我们可能掩盖了与库无关的问题,例如" OutOfMemoryException",我们确实更喜欢冒泡,以便可以通知用户,等等。另一方面,如果我们正在谈论的是在main()方法中捕获异常的方法,该方法捕获异常,先显示该异常,然后退出...好吧,在这里捕获几乎所有异常都是安全的。

捕获所有异常的最重要规则是,我们绝不应该默默地吞下所有异常。在Java中是这样的:

try { 
    something(); 
} catch (Exception ex) {}

或者在Python中:

try:
    something()
except:
    pass

因为这些可能是一些最难追踪的问题。

一个好的经验法则是,我们应该只捕获可以正确处理的异常。如果我们不能完全处理异常,则应让它冒犯给可以处理的人。

回答

是的! (除了应用程序的"顶部")

通过捕获异常并允许代码继续执行,我们表示我们知道如何处理和规避或者解决特定问题。我们是在说这是可恢复的情况。捕获Exception或者SystemException意味着我们将捕获诸如IO错误,网络错误,内存不足错误,代码丢失错误,空指针取消引用之类的问题。说我们可以处理这些是一个谎言。

在一个组织良好的应用程序中,这些不可恢复的问题应在堆栈的最高处进行处理。

另外,随着代码的发展,我们不希望函数捕获新的异常,该异常将来会添加到被调用的方法中。

回答

在我看来,我们应该捕获所有期望的异常,但是该规则适用于除接口逻辑之外的所有内容。在调用堆栈的整个过程中,我们可能应该创建一种捕获所有异常的方法,进行一些日志记录/提供用户反馈,并在需要和可能的情况下正常关闭。

没有比将用户不友好的堆栈跟踪转储到屏幕而崩溃的应用程序更糟糕的了。它不仅使(也许是不需要的)洞察代码,而且使最终用户感到困惑,有时甚至将它们吓到竞争的应用程序。

回答

捕获所有异常的问题在于,我们可能正在捕获意外的异常,或者实际上是不应捕获的异常。事实是,任何类型的异常都表明出了点问题,我们必须先对其进行分类,然后再继续进行,否则可能会遇到数据完整性问题和其他不易查找的错误。

举一个例子,在一个项目中,我实现了一种称为CriticalException的异常类型。这表示需要开发人员和/或者管理人员进行干预的错误情况,否则客户将被错误地记帐,否则可能会导致其他数据完整性问题。当仅记录异常还不够,并且需要发送电子邮件警报时,也可以在其他类似情况下使用它。

另一位没有正确理解异常概念的开发人员然后包装了一些代码,这些代码有可能在通用的try ... catch块中抛出此异常,该块会丢弃所有异常。幸运的是,我发现了它,但是它可能会导致严重的问题,尤其是因为本来应该抓住的"非常不常见"的极端情况比我预期的要普遍得多。

因此,通常来说,捕获通用异常是不好的,除非我们100%确信我们确切知道将在何种情况下抛出哪种异常。如有疑问,请让它们冒泡到顶级异常处理程序。

这里类似的规则是永远不会抛出System.Exception类型的异常。我们(或者其他开发人员)可能希望在调用堆栈中更高的位置捕获特定的异常,同时让其他人通过。

(但是,有一点要注意。在.NET 2.0中,如果线程遇到任何未捕获的异常,它将卸载整个应用程序域。因此,应将线程的主体包装在通用的try ... catch块中并传递全局异常处理代码中捕获的所有异常。)

回答

关于此问题,已经进行了许多哲学讨论(更像是论据)。我个人认为,最糟糕的事情是吞下异常。下一个最糟糕的情况是,允许异常气泡冒泡到表面,使用户获得充满技术性庞然大物的讨厌屏幕。