第 20 章 异常和状态管理
第 20 章 异常和状态管理
NyxX第 20 章 异常和状态管理
本章内容
- 定义“异常”
- 异常处理机制
System.Exception类- FCL 定义的异常类
- 抛出异常
- 定义自己的异常类
- 用可靠性换取开发效率
- 设计规范和最佳实践
- 未处理的异常
- 对异常进行调试
- 异常处理的性能问题
- 约束执行区域(CER)
- 代码协定
20.2 异常处理机制
以下 C# 代码展示了异常处理机制的标准用法,可通过它对异常处理代码块及其用途产生初步认识。代码后面的各小节将正式描述 try、catch 和 finally 块及其用途,并提供关于它们的一些注意事项。
1 | private void SomeMethod() { |
20.2.1 try块
20.2.2 catch块
catch 关键字后的圆括号中的表达式称为捕捉类型。C# 要求捕捉类型必须是System.Exception或者它的派生类型。
CLR 自上而下搜索匹配的 catch 块,所以应该将具体的异常放在顶部。
当 CLR 找到匹配的 catch 块时,会执行内层所有 finally 块中的代码。所有内层 finally 块执行完毕后,匹配异常的 catch 块中的代码才开始执行。
在 catch 块的末尾,我们有以下三个选择。
重新抛出相同的异常,向调用栈高一层的代码通知该异常的发生。
抛出一个不同的异常,向调用栈高一层的代码提供更丰富的异常信息。
让线程从
catch块的底部退出③。
20.2.3 finally块
finally块包含的是保证会执行的代码①。一般在 finally 块中执行try块的行动所要求的资源清理操作。
try 块并不一定要关联 finally 块。 try 块的代码有时并不需要任何清理工作。但是,只要有 finally 块,它就必须出现在所有 catch 块之后,而且一个 try 块最多只能够关联一个 finally 块。
C# 编译器只允许代码抛出从 Exception 派生的对象,但是,CLR 实际允许抛出任何类型的实例。
20.3 System.Exception 类
20.4 FCL 定义的异常类
Microsoft 本来是打算将 System.Exception 类型作为所有异常的基类型,而另外两个类型 System.SystemException 和 System.ApplicationException 是唯一直接从 Exception 派生的类型。另外,CLR 抛出的所有异常都从 SystemException派生,应用程序抛出的所有异常都从 ApplicationException 派生。这样就可以写一个 catch 块来捕捉 CLR 抛出的所有异常或者应用程序抛出的所有异常。
但是,规则没有得到严格遵守。有的异常类型直接从 Exception 派生(IsolatedStorageException);CLR 抛出的一些异常从 ApplicationException 派生 (TargetInvocationException);而应用程序抛出的一些异常从 SystemException 派生(FormatException)。这根本就是一团糟。结果是 SystemException 类型和 ApplicationException 类型根本没什么特殊含义。Microsoft 本该及时将它们从异常类的层次结果中移除,但现在已经不能那样做了,因为会破坏现有的代码对这两个类型的引用。
20.5 抛出异常
强烈建议定义浅而宽的异常类型层次结构,以创建尽量少的基类。原因是基类的主要作用就是将大量错误当作一个错误,而这通常是危险的。基于同样的考虑,永远都不要抛出一个System.Exception 对象②,抛出其他任何基类异常类型时也要特别谨慎。





