第21章 异常处理

C#提供了一种类型安全的异常处理方式,可以提供对系统级和应用程序级的异常处理。但并非所有的.NET Framework操作都通过引发异常来指示出现错误。例如,对非常常见的错误情况返回空。File.Open方法如果没找到文件,则返回空;但如果文件被锁定,则会引发异常。

C#中的异常处理和C++中的处理机制有几分相似,但也不尽相同,区别主要体现在以下几点:

❑在C#中,所有的异常都是使用一个异常类型的实例对象表示的,这些异常类型都继承自System.Exception类型,或者直接使用System.Exception类型的实例对象;而在C++中,任意类型的任意值都可以表示一个异常。

❑在C#中,位于finally块中的代码可以保证不管代码是正常结束,还是进入异常处理代码块,其中的语句均会被执行。换句话说,无论是否产生异常,finally块都会被执行。因此,在finally语句中放置资源回收的代码是一个不错的主意,当然,也可以执行其他必要的操作。而在C++中并没有相对应的机制。

❑在C#中,像溢出、空指针、除数为零这样的系统级别的异常,BCL都提供了预定义的异常类供使用,其使用方式和应用级别的异常处理完全相同。例如,两个数相除,当除数为零时会引发一个System.DivideByZeroException异常,溢出时引发System.OverflowException异常,这些异常类都是在BCL中预定义的。

21.1 异常类

System.Exception类是所有异常类的基类,例如,当显式类型转换失败或无效的时候,CLR将引发System.InvalidCastException异常,而当找不到文件或目录时,将引发System.IO.DirectoryNotFoundException异常。

其中,System.Exception类有一些属性值得注意(如图21-1所示),这些属性被所有从此类派生的异常类共享,这些属性是:

第21章 异常处理 - 图1

图 21-1 System.Exception类

❑Message:一个只读字符串,此属性为当前的异常提供了描述性信息;

❑InnerException:一个Exception类型的只读属性,如果它的值不为null,则可以通过它的值获取导致当前异常的异常实例;反之,如果其值为null,则表示当前异常不是由其他异常引发的;

❑StackTrace:一个只读字符串,此属性描述了异常发生时调用堆栈的内容,其中首先显示最近的方法调用。

可以使用Exception类的构造函数,为异常实例指定Message和InnerException。它的构造函数如下:


public Exception(

string message,

Exception innerException


为了区分系统级异常和应用级异常,BCL提供了两种直接继承自System.Exception的异常类型:

❑System.SystemException:由CLR引发的异常都继承自SystemException,例如InvalidCast-Exception、InvalidOperationException等;

❑System.ApplicationException:由用户应用程序(不是CLR)引发的异常,因此我们编写的自定义异常应从ApplicationException继承。

BCL中提供的一部分预定义异常如图21-2所示。

第21章 异常处理 - 图2

图 21-2 BCL中从SystemException派生的异常类型

图21-2是部分异常的继承结构图,可以看到SystemException和ApplicationException都是直接派生自Exception类,而InvalidCastException、InvalidOperationException等派生自SystemException,OverflowException和DivideByZeroException则从ArithmeticException派生而来。