有时我不知道我应该抛出什么类型的异常。所以我通常会抛出Exception()。有没有关于这个的好文章?
6 回答
抛出通用异常的问题在于它限制了代码在堆栈中进一步正确处理它的能力(即最佳实践是在回退之前捕获最具体的异常,并且只捕获您可以处理的内容)。
Jeffrey Richter 在CLR 中通过 C#进行异常处理(包括有关 System.Exception 命名空间的信息)的精彩部分
Cwalina 和 Abrahms 的“框架设计指南”很好地涵盖了这个主题(恕我直言)。
可在此处免费在线获取,或在此处(英国)或此处(美国)获取书籍(非免费) 。查看标题为“例外设计指南”的部分。
好吧,你不应该做的一件事就是扔Exception
自己。
始终寻找合适的子类。
我不知道有任何出版物明确说明何时抛出哪个异常,但ArgumentException
应该InvalidOperationException
处理您的大多数情况。
如果出现单独的案例,请针对单独的案例提出单独的问题。
如果你没有尝试从错误中恢复,你可以抛出一个Exception
带有字符串的字符串来告诉你出了什么问题。(或者,无论发生什么错误,您都将执行相同的操作)。
除了通过使用新的异常名称而不是将其放入消息中来让程序员清楚出了什么问题之外,异常还可以包含帮助您从特定异常中恢复的数据。
例如, anArgumentNullException
有一个 property ParamName
,你应该在抛出异常时设置它。当调用者捕获它时,他可以查找该属性并决定为导致错误的参数传递一个新值,或者可以打印相关错误以通知程序员出了什么问题。
不幸的是,异常很少被充分利用(在许多开源 API 等中),并且通常只是简单地插入以告知程序员出了什么问题。如果您不打算ParamName
在捕获该属性时阅读该属性,则这两者之间没有太大区别。(很多人不会打扰,Exception
反正只抓一个)。
throw new ArgumentNullException("arg1");
throw new Exception("arg1 is null");
完全从错误中恢复可能很困难,但是在某些应用程序中,您可能会发现创建自定义异常以提供您需要的所有详细信息是可取的。
现在,我只需要Exception
在 VS 中进行对象浏览器搜索,看看已经有什么。他们的名字很容易解释,所以你应该能够挑选出合适的东西。
我建议根据系统状态将异常分为几类:
- 该方法以这样的方式失败,以至于它什么也没做。任何基础数据的状态都没有受到干扰,并且可能是有效的。典型场景:尝试从集合中检索一个不存在的对象,或者添加一个已经存在的对象。另一种可能的情况:在不应该导致任何数据丢失的情况下发生通信超时(如果问题仅仅是另一端太慢,那么重试操作可能会成功)。
- 该方法以可能已经扰乱了底层数据结构的方式失败,或者底层数据结构之前可能已被破坏。除非采取步骤来验证它,否则不应尝试使用此数据结构进行进一步的操作。另一种可能的情况:当记录已被部分检索时发生通信超时,并且部分检索的数据现在丢失了。根据协议,可能需要对连接执行一些恢复操作,或者关闭它并启动一个新连接。
- 系统状态出现严重问题,可能无法恢复。
不幸的是,现有的 .net 异常不符合这种模式。如果有一个 ExceptionBase 类型可以派生出 ThreadAbortException、CpuHasCaughtFireException 和“正常”异常,并且所有“正常”异常都派生自 Exception,那就太好了。我知道 .net 4.0 在这样的设计中有些杂乱无章,但我不知道确切的机制。无论如何,我建议任何用户定义的异常都应该像上面那样分成组,每个组中的所有异常都共享一个不同于其他组的共同祖先。
Krzysztof Cwalina(“Microsoft .NET Framework 团队的首席架构师”)有一篇名为“选择正确的异常类型”的文章对此进行了阐述。它处理选择正确的异常抛出和创建自定义异常的指导。