21 个异常
21.1 常规
C# 中的异常提供了一种结构化、统一且类型安全的方法来处理系统级别和应用程序级错误条件。
21.2 异常原因
可以通过两种不同的方式引发异常。
- 语句
throw
(§13.10.6)立即无条件地引发异常。 Control 永远不会立即到达紧跟在后面的throw
语句。 - 在处理 C# 语句和表达式期间出现的某些异常情况会导致在无法正常完成操作时引发异常。 有关可通过这种方式引发的各种异常的列表,请参阅 §21.5 。
示例:如果分母为零,整数除法运算(§12.10.3)将
System.DivideByZeroException
引发。 end 示例
21.3 System.Exception 类
该 System.Exception
类是所有异常的基类型。 此类具有一些值得注意的属性,所有异常共享:
Message
是类型的string
只读属性,其中包含异常原因的可读说明。InnerException
是类型的Exception
只读属性。 如果其值为非null
,则引用导致当前异常的异常。 (也就是说,当前异常是在处理 .的 catch 块中引发的InnerException
。否则,其值为null
,指示此异常不是由另一个异常引起的。 以这种方式链接在一起的异常对象数可以是任意的。
可以在调用实例 System.Exception
构造函数时指定这些属性的值。
21.4 如何处理异常
异常由 try
语句处理(§13.11)。
引发异常(§21.2)时,系统会根据异常的运行时类型来搜索可处理异常的最接近的 catch 子句。 首先,按词法try
搜索当前方法,并按顺序考虑语句的try
关联catch
子句。 如果失败,则调用当前方法的方法将搜索一个词法封闭语句,该语句将调用当前方法的点括 try
起来。 此搜索一直持续到找到一个 catch
子句,该子句可以通过命名同一类或基类的异常类(即引发的异常的运行时类型)来处理当前异常。 catch
不命名异常类的子句可以处理任何异常。
找到匹配 catch
子句后,系统将准备将控制权传输到子句的第一个语句 catch
。 在子句执行catch
开始之前,系统将首先按顺序执行与try
语句关联的任何finally
子句,这些子句比捕获异常的语句更嵌套。
如果未找到匹配 catch
子句:
- 如果搜索匹配
catch
子句达到静态构造函数(§15.12)或静态字段初始值设定项,则会在触发静态构造函数调用的点引发 aSystem.TypeInitializationException
。 内部异常System.TypeInitializationException
包含最初引发的异常。 - 否则,如果在终结器执行期间发生异常,并且未捕获该异常,则行为未指定。
- 否则,如果搜索匹配
catch
子句到达最初启动线程的代码,则将终止线程的执行。 此类终止的影响是实现定义的。
21.5 常见异常类
某些 C# 操作会引发以下异常。
异常类型 | 描述 |
---|---|
System.ArithmeticException |
算术运算期间出现的异常的基类,例如 System.DivideByZeroException 和 System.OverflowException 。 |
System.ArrayTypeMismatchException |
当存储区进入数组失败时引发,因为存储元素的类型与数组的类型不兼容。 |
System.DivideByZeroException |
尝试将整数值除以零时引发。 |
System.IndexOutOfRangeException |
尝试通过小于零或超出数组边界的索引为数组编制索引时引发。 |
System.InvalidCastException |
当从基类型或接口到派生类型的显式转换在运行时失败时引发。 |
System.NullReferenceException |
当引用以导致需要引用对象的方式使用时 null 引发。 |
System.OutOfMemoryException |
尝试分配内存(通过 new )失败时引发。 |
System.OverflowException |
checked 上下文中的算术运算溢出时引发。 |
System.StackOverflowException |
在执行堆栈耗尽时引发的挂起调用过多;通常表示非常深或未绑定的递归。 |
System.TypeInitializationException |
当静态构造函数或静态字段初始值设定项引发异常时引发,并且不存在 catch 用于捕获它的子句。 |