处理和引发异常

应用程序必须能够以一致的方式处理在执行期间发生的错误。 公共语言运行时提供了一个用于以统一方式向应用程序通知错误的模型。 所有的 .NET Framework 操作都通过引发异常来指示出现错误。

本主题包含以下各节:

  • .NET Framework 中的异常

  • 异常与 传统的错误处理方法

  • 运行时如何管理异常

  • 筛选运行时异常

  • 相关主题

  • 参考

.NET Framework 中的异常

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

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

返回页首

异常与传统的错误处理方法

传统上,语言的错误处理模型依赖于语言检测错误和查找错误处理程序的独特方式,或者依赖于操作系统提供的错误处理机制。 运行时实现的异常处理具有以下特点:

  • 处理异常时不用考虑生成异常的语言或处理异常的语言。

  • 异常处理时不要求任何特定的语言语法,而是允许每种语言定义自己的语法。

  • 允许跨进程甚至跨计算机边界引发异常。

与其他错误通知方法(如返回代码)相比,异常具有若干优点。 不再有出现错误而不被人注意的情况。 无效值不会继续在系统中传播。 不必检查返回代码。 可以轻松添加异常处理代码,以增加程序的可靠性。 最后,运行时的异常处理比基于 Windows 的 C++ 错误处理更快。

由于执行线程例行地遍历托管代码块和非托管代码块,因此运行时可以在托管代码或非托管代码中引发或捕捉异常。 非托管代码可以同时包含 C++ 样式的 SEH 异常和基于 COM 的 HRESULT。

运行时如何管理异常

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

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

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

  • finally 处理程序,每当块退出时它都会执行,而不论退出是由正常控制流引起的还是由未经处理的异常引起的。

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

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

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

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

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

  1. 运行时在数组中搜索执行下列操作的第一个受保护块:

    • 保护包含当前执行的指令的区域。

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

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

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

返回页首

筛选运行时异常

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

类型筛选的处理程序管理特定类型的异常(或从该异常派生的类)。 下面的示例说明一个旨在捕获特定异常(此示例中为 FileNotFoundException)的类型筛选的处理程序。

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

用户筛选的异常处理程序根据您为异常定义的要求捕捉和处理异常。 有关按此方式筛选异常的更多信息,请参见在 Catch 块中使用特定异常

返回页首

相关主题

标题

说明

异常类和属性

描述异常对象的元素。

异常层次结构

描述一些异常,大多数异常都从这些异常派生。

异常处理基础知识

解释如何使用 catch、throw 和 finally 语句处理异常。

处理异常的最佳做法

描述建议的异常处理方法。

处理 COM 互操作异常

描述如何处理在非托管代码中引发和捕捉的异常。

如何:映射 HRESULT 和异常

描述异常在托管代码和非托管代码之间的映射。

返回页首

参考

System.Exception

System.ApplicationException

System.SystemException