11.1 什么是异常
异常是程序中的运行时错误,它违反了一个系统约束或应用程序约束,或出现了在正常操作时未预料的情形。
如果程序没有提供处理该异常的代码,系统会挂起这个程序。
11.2 try语句
try语句用来指明被异常保护的代码块,并提供代码以处理异常,如果它们发生的话。
try语句由三个部分组成:
- try块包含正被异常保护的代码。
- catch子句部分含有一个或多个catch子句。这些是处理异常的代码块。它们也称为是异常处理程序。
- finally块含有在所有情况下都要被执行的代码,无论有没有异常发生。
处理异常
把代码放在一个try块中,并提供一个简单的catch子句,以处理该异常。当异常发生时,它被捕获并在catch块中处理。
11.3 异常类
有许多不同类型的异常可以在程序中发生。BCL定义了许多类,每一个类代表一个指定的异常类型。当一个异常发生时,CLR:
- 创建该类型的异常对象。
- 寻找适当的catch子句处理它。
异常对象含有只读属性,带有导致该异常的信息。常用属性:
- Message :(string) 含有解释异常原因的消息。
- StackTrace:(string) 含有描述异常发生在何处的消息。
- InnerException:(Exception)如果当前异常是由另一个异常引起的,这个属性包含前一个异常的引用。
- HelpLink: (string)被应用程序定义的异常设置,为异常原因信息提供URN或URL。
- Source:(string)如果没有被应用程序定义的异常设定,那么这个属性含有异常起源所在的程序集的名称。
11.4 catch子句
catch子句处理异常。它有三种形式,允许不同级别的处理。
11.5 finally块
- 一般catch子句能接受任何异常,但不能确定引发异常的类型。这只允许对任何可能发生的异常的普通处理和清理。
- 特定catch子句形形式把一个异常类的名称作为参数。它匹配该指定类或派生自它的异常类的异常。
- 带对象的特定catch子句提供最多的关于异常的信息。它匹配该指定类的异常,或派生自它的异常类的异常。它还给出一个异常实例,称为异常变量,它是一个对CLR创建的异常对象的引用。可以在catch子句块内部访问异常变量的属性,以获取关于引起的异常的详细信息。
当异常发生时,系统按顺序搜索catch子句的列表,第一个匹配该异常对象类型的catch子句被执行。因此,catch子句的排序有两个重要的规则。它们是:
- 特定catch子句必须以一种顺序排列,最明确的异常类型第一,直到最普通的类型。
- 如果有一个一般catch子句,它必须是最后一个,并且在所有特定catch子句之后。使用一般catch子句是不好的。应该尽可能使用特定catch子句。一般catch子句通过让程序继续隐藏错误,让程序处于一种未知的状态。
如果程序的控制流进入一个带finally块的try语句,那么finally始终会被执行。
- 如果在try块内部没有异常发生,那么在try块的结尾,控制流跳过任何catch子句并到finally块。
- 如果在try块内部发生了异常,那么在catch子句段中无论哪一个适当的catch子句被执行,接着就是finally块的执行。
即使try块中有return语句,finally块也总是会在返回到调用代码之前执行。
11.6 为异常寻找处理代码
当程序产生一个异常,系统查一看该程序是否为它提供了一个处理代码。
- 如果在try块内发生了异常,系统会查看是否有任何一个catch子句能处理该异常。
- 如果找到了适当的catch子句:
- 该catch子句被执行。
- 如果有finally块,那么它被执行。
- 执行在try语句的尾部继续。
11.7 更进一步搜索
如果异常在一个没有被try语句保护的代码段中产生,或如果try语句没有匹配的异常处理程序,系统将不得不更进一步寻找匹配的处理代码。为此它会按顺序搜索调用栈,以看看是否存在带匹配的处理代码的封闭try块。
一般法则
11.8 抛出异常
11.9 不带异常对象的抛出可以使用throw语句使代码显式地引发一个异常。throw语句的语法如下:
throw ExceptionObject;
throw语句还可以不带异常对象使用,在catch块内部:
- 这种形式重新抛出当前异常,系统继续它的搜索,为该异常寻找另外的处理代码。
- 这种形式只能用在catch语句内部。