异常概述

更新:2007 年 11 月

异常是程序执行时遇到的任何错误情况或意外行为。以下这些情况都可以引发异常:您的代码或调用的代码(如共享库)中有错误,操作系统资源不可用,公共语言运行库遇到意外情况(如无法验证代码),等等。对于这些情况,应用程序可以从其中一些恢复,而对于另一些,则不能恢复。尽管可以从大多数应用程序异常中恢复,但不能从大多数运行库异常中恢复。

在 .NET Framework 中,异常是从 Exception 类类继承的对象。异常从发生问题的代码区域引发,然后沿堆栈向上传递,直到应用程序处理它或程序终止。有关使用 .NET Framework 处理异常的更多信息,请参见 Exception 类主题。

运行库如何管理异常

运行库使用基于异常对象和受保护代码块的异常处理模型。出现异常时,创建一个 Exception 对象来表示该异常。

运行库为每个可执行文件创建一个异常信息表。在异常信息表中,可执行文件的每个方法都有一个关联的异常处理信息数组(可以为空)。数组中的每一项描述一个受保护的代码块、任何与该代码关联的异常筛选器和任何异常处理程序(Catch 语句)。此异常表非常有效,在没有发生异常时,在处理器时间或内存使用上没有性能损失。仅在异常发生时使用资源。

异常信息表对于受保护的块有四种类型的异常处理程序:

  • Finally 处理程序,它在每次块退出时都执行,不论退出是由正常控制流引起的还是由未处理的异常引起的。

  • 错误处理程序,它在异常发生时必须执行,但在正常控制流完成时不执行。

  • 类型筛选的处理程序,它处理指定类或该类的任何派生类的任何异常。

  • 用户筛选的处理程序,它运行用户指定的代码,来确定异常应由关联的处理程序处理还是应传递给下一个受保护的块。

每种语言根据自己的规范实现这些异常处理程序。例如,Visual Basic 2005 通过 Catch 语句中的变量比较(使用 When 关键字)提供对用户筛选的处理程序的访问;C# 不实现用户筛选的处理程序。

异常发生时,运行库开始执行由下列两步组成的过程:

  1. 运行库在数组中搜索满足下列条件的第一个受保护块:

    • 保护包含当前执行的指令的区域,而且

    • 包含异常处理程序或包含处理异常的筛选器。

  2. 如果出现匹配项,运行库创建一个 Exception 对象来描述该异常。然后运行库执行位于发生异常的语句与处理该异常的语句之间的所有 Finally 语句或错误处理语句。请注意,异常处理程序的顺序很重要:最里面的异常处理程序最先计算。还请注意,异常处理程序可以访问捕捉异常的例程的局部变量和本地内存,但引发异常时的任何中间值都会丢失。

    如果当前方法中没有出现匹配项,则运行库搜索当前方法的每一个调用方,并沿着堆栈一直向上查找。如果任何调用方都没有匹配项,则运行库允许调试器访问该异常。如果调试器不能附加到该异常,则运行库引发 UnhandledException 事件。如果没有 UnhandledException 事件的侦听器,则运行库转储堆栈跟踪并结束程序。

筛选运行库异常

可以按类型或按某些用户定义的条件对捕捉和处理的异常进行筛选。

类型筛选的处理程序处理特定类型的异常(或从该异常派生的类)。最常见形式的类型筛选的异常处理程序指定仅捕捉特定类型的异常。

下面的示例说明一个旨在捕获特定异常(此例中为 FileNotFoundException)的异常处理程序。

Catch e As FileNotFoundException
   Console.WriteLine("[Data File Missing] {0}", e)
catch(FileNotFoundException e) {
    Console.WriteLine("[Data File Missing] {0}", e);
}

用户筛选的异常处理程序根据您为异常定义的要求捕捉和处理异常。在 Visual Basic 2005 中,这些处理程序将 Catch 语句和 When 关键字结合使用。有关用此方法筛选异常的详细信息,请参见在 Catch 块中使用特定异常

请参见

概念

异常类和属性

异常层次结构

处理异常的最佳做法

其他资源

异常处理基础知识

处理和引发异常