C#:关于抛出适当类型异常的文章

C#:关于抛出适当类型异常的文章,c#,exception,article,C#,Exception,Article,有时我不知道我应该抛出哪种类型的异常。所以我通常抛出Exception()。有关于这方面的好文章吗 引发泛型异常的问题在于,它限制了代码在堆栈上进一步正确处理它的能力(即,最佳实践是在回退之前捕获最具体的异常,并且只捕获您可以处理的异常) Jeffrey Richter在中有一个关于异常处理(包括有关System.exception命名空间的信息)的优秀章节。好吧,你不应该做的一件事就是抛出异常本身。 始终寻找合适的子类 我不知道有任何出版物详细说明了何时抛出哪个异常,但是ArgumentExc

有时我不知道我应该抛出哪种类型的异常。所以我通常抛出Exception()。有关于这方面的好文章吗

引发泛型异常的问题在于,它限制了代码在堆栈上进一步正确处理它的能力(即,最佳实践是在回退之前捕获最具体的异常,并且只捕获您可以处理的异常)


Jeffrey Richter在

中有一个关于异常处理(包括有关System.exception命名空间的信息)的优秀章节。好吧,你不应该做的一件事就是抛出异常本身。
始终寻找合适的子类

我不知道有任何出版物详细说明了何时抛出哪个异常,但是
ArgumentException
invalidooperationexception
应该处理您的大多数情况


如果出现不同的情况,请分别提问。

如果您没有尝试从错误中恢复,您可以抛出带有字符串的
异常来告诉您出了什么问题。(或者,无论发生什么错误,您都将执行相同的操作)

除了通过使用新的异常名称而不是将其放在消息中使程序员清楚地知道哪里出了问题之外,异常还可以包含数据以帮助您从特定异常中恢复

例如,
ArgumentNullException
有一个属性
ParamName
,您应该在抛出异常时设置该属性。当调用者捕捉到它时,他可以查找这个属性并决定为导致错误的参数传递一个新值,或者打印一个相关的错误来通知程序员出了什么问题

不幸的是,异常很少被充分利用(在许多开源API等中),并且常常只是被插入以通知程序员出了什么问题。如果捕获时不打算读取
ParamName
属性,则这两个属性之间没有太大区别。(许多人不会打扰,而且只会捕获一个
异常

很难完全从错误中恢复,但在某些应用程序中,您可能会发现创建自定义异常是可取的,它可以提供您所需的所有详细信息

现在,我只想在VS中的对象浏览器搜索中输入
Exception
,看看已经有了什么。他们的名字不言自明,所以你应该能够挑选出合适的东西。

Cwalina和Abrahms的“框架设计指南”很好地涵盖了这个主题(IMHO)


它可以在网上免费获得,也可以在书(不是免费的)上获得。查看“异常设计指南”一节。我建议根据系统状态将异常分为几个类别:

  • 这个方法失败了,什么也没做;任何基础数据的状态都没有受到干扰,可能是有效的。典型场景:尝试从集合中检索不存在的对象,或添加已经存在的对象。另一种可能的情况是:在不应导致任何数据丢失的情况下(如果问题仅仅是另一端速度太慢,则重试操作可能会成功),通信超时。
  • 该方法失败的方式可能干扰了底层数据结构,或者底层数据结构以前可能已损坏。除非采取步骤验证此数据结构,否则不应尝试对其进行进一步操作。另一种可能的情况是:当部分检索到记录时,通信超时发生,而部分检索到的数据现在丢失。根据协议的不同,可能需要对连接执行一些恢复操作,或者关闭连接并启动一个新的恢复操作。
  • 系统状态出现严重错误,可能无法恢复。
    不幸的是,现有的.net异常不适合这种模式;如果有一个类型ExceptionBase,像ThreadAbortException、CpuHasCaughtFireException和“正常”异常都是从中派生出来的,而所有“正常”异常都是从Exception派生出来的,那就太好了。我知道.NET4.0在这样的设计中有些笨拙,但我不知道确切的机制。在任何情况下,我都建议用户定义的异常都应按上述方式划分为多个组,每个组中的所有异常都有一个与其他组不同的共同祖先。

    Krzysztof Cwalina(“Microsoft.NET Framework团队的首席架构师”)有一篇文章对此进行了说明。它涉及选择要抛出的正确异常以及创建自定义异常的指导。

    Richter和Cwalina都提供了关于何时/何时抛出的建议。
    throw new ArgumentNullException("arg1");
    throw new Exception("arg1 is null");