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)或静态字段初始值设定项,则会在触发静态构造函数调用的点引发 a System.TypeInitializationException 。 内部异常 System.TypeInitializationException 包含最初引发的异常。
  • 否则,如果在终结器执行期间发生异常,并且未捕获该异常,则行为未指定。
  • 否则,如果搜索匹配 catch 子句到达最初启动线程的代码,则将终止线程的执行。 此类终止的影响是实现定义的。

21.5 常见异常类

某些 C# 操作会引发以下异常。

异常类型 描述
System.ArithmeticException 算术运算期间出现的异常的基类,例如 System.DivideByZeroExceptionSystem.OverflowException
System.ArrayTypeMismatchException 当存储区进入数组失败时引发,因为存储元素的类型与数组的类型不兼容。
System.DivideByZeroException 尝试将整数值除以零时引发。
System.IndexOutOfRangeException 尝试通过小于零或超出数组边界的索引为数组编制索引时引发。
System.InvalidCastException 当从基类型或接口到派生类型的显式转换在运行时失败时引发。
System.NullReferenceException 当引用以导致需要引用对象的方式使用时 null 引发。
System.OutOfMemoryException 尝试分配内存(通过 new)失败时引发。
System.OverflowException checked 上下文中的算术运算溢出时引发。
System.StackOverflowException 在执行堆栈耗尽时引发的挂起调用过多;通常表示非常深或未绑定的递归。
System.TypeInitializationException 当静态构造函数或静态字段初始值设定项引发异常时引发,并且不存在 catch 用于捕获它的子句。