表示在应用程序执行期间发生的错误。
命名空间:System
程序集:mscorlib(在 mscorlib.dll 中)
[SerializableAttribute] [ComVisibleAttribute(true)] [ClassInterfaceAttribute(ClassInterfaceType.None)] public class Exception : ISerializable, _Exception
此类是所有异常的基类。当发生错误时,系统或当前正在执行的应用程序通过引发包含关于该错误的信息的异常来报告错误。异常发生后,将由该应用程序或默认异常处理程序进行处理。
公共语言运行库提供一种异常处理模型,该模型基于对象形式的异常表示形式,并且将程序代码和异常处理代码分到 try 块和 catch 块中。可以有一个或多个 catch 块,每个块都设计为处理一种特定类型的异常,或者将一个块设计为捕捉比其他块更具体的异常。
如果应用程序将处理在执行应用程序代码块期间发生的异常,则代码必须放置在 try 语句中。try 语句中的应用程序代码是 try 块。处理由 try 块引发的异常的应用程序代码放在 catch 语句中,称为 catch 块。零个或多个 catch 块与一个 try 块相关联,每个 catch 块均包含一个确定该块处理的异常类型的类型筛选器。
在 try 块中出现异常时,系统按所关联 catch 块在应用程序代码中出现的顺序搜索它们,直到定位到处理该异常的 catch 块为止。如果某 Catch 块的类型筛选器指定 T 或任何派生出 T 的类型,则该 catch 块处理 T 类型的异常。系统在找到第一个处理该异常的 catch 块后即停止搜索。因此,正如本节后面的示例所演示的那样,在应用程序代码中处理某类型的 catch 块必须在处理其基类型的 catch 块之前指定。处理 System.Exception 的 Catch 块最后指定。
如果当前 try 块所关联的所有 catch 块均不处理该异常,且当前 try 块嵌套在当前调用的其他 try 块中,则搜索与下一个封闭 try 块相关联的 catch 块。如果没有找到用于该异常的 catch 块,则系统搜索当前调用中前面的嵌套级别。如果在当前调用中没有找到用于该异常的 catch 块,则将该异常沿调用堆栈向上传递,搜索上一个堆栈帧来查找处理该异常的 catch 块。继续搜索调用堆栈,直到该异常得到处理或调用堆栈中没有更多的帧为止。如果到达调用堆栈顶部却没有找到处理该异常的 catch 块,则由默认的异常处理程序处理该异常,然后应用程序终止。
异常类型支持下面的功能:
-
描述错误的可读文本。当异常发生时,运行库产生文本消息通知用户错误的性质并提供解决该问题的操作建议。此文本消息保存在异常对象的 Message 属性中。在创建异常对象过程中,可以将文本字符串传递给构造函数以描述该特定异常的详细信息。如果没有向构造函数提供错误信息参数,则将使用默认错误信息。
-
发生异常时调用堆栈的状态。StackTrace 属性包含可以用来确定代码中错误发生位置的堆栈跟踪。堆栈跟踪列出所有调用的方法和源文件中这些调用所在的行号。
基类 Exception 下存在两类异常:
-
从 SystemException 派生的预定义公共语言运行库异常类。
-
从 ApplicationException 派生的用户定义的应用程序异常类。
Exception 包含很多属性,可以帮助标识异常的代码位置、类型、帮助文件和原因:StackTrace、InnerException、Message、HelpLink、HResult、Source、TargetSite 和 Data。
当在两个或多个异常之间存在因果关系时,InnerException 属性会维护此信息。作为对此内部异常的反应将引发外部异常。处理外部异常的代码可利用以前的内部异常的信息更妥当地处理错误。关于异常的补充信息可以存储在 Data 属性中。
应本地化在创建异常对象过程中传递给构造函数的错误信息字符串,这种字符串可以使用 ResourceManager 从资源文件提供。有关本地化资源的更多信息,请参见“System.Resources 命名空间概述”和“打包和部署资源”。
若要向用户提供有关异常发生原因的大量信息,可以使用 HelpLink 属性保存帮助文件的 URL(或 URN)。
Exception 使用具有值 0x80131500 的 HRESULT COR_E_EXCEPTION。
有关 Exception 实例的初始属性值列表,请参见 Exception 构造函数。
性能注意事项
引发或处理异常时,将使用大量的系统资源和执行时间。引发异常只是为了处理确实异常的情况,而不是为了处理可预知的事件或流控制。例如,如果方法参数无效,而应用程序需要使用有效的参数调用方法,则可以引发异常。无效的方法参数意味着出现了异常情况。相反,用户偶尔会输入无效数据,这是可以预见的,因此如果用户输入无效,则不要引发异常。在这种情况下,请提供重试机制以便用户输入有效输入。
仅对特别条件引发异常,然后在应用于大多数应用程序的常规异常处理程序中捕捉异常,而不是在应用于特定异常的处理程序中捕捉异常。此方法的基础在于,大多数错误都可以通过验证以及与错误接近的错误处理代码进行处理;不需要引发和捕捉异常。通用目的异常处理程序捕捉的是在应用程序任意位置引发的、真正不可预期的异常。
此外,返回代码正常时不要引发异常;不要将返回代码转换为异常;也不要例行公事地捕捉异常、忽略异常,然后继续处理。
下面的代码示例说明如何定义 catch 块来处理 ArithmeticException 错误。此 catch 块还捕捉 DivideByZeroException 错误,因为 DivideByZeroException 从 ArithmeticException 派生,且没有为 DivideByZeroException 错误显式定义 catch 块。
using System; class ExceptionTestClass { public static void Main() { int x = 0; try { int y = 100/x; } catch (ArithmeticException e) { Console.WriteLine("ArithmeticException Handler: {0}", e.ToString()); } catch (Exception e) { Console.WriteLine("Generic Exception Handler: {0}", e.ToString()); } } }
ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero. at ExceptionTestClass.Main()
Visual Basic 代码的输出如下所示:
ArithmeticException Handler: System.OverflowException: Exception of type System.OverflowException was thrown. at ExceptionTestClass.Main()
发生非致命应用程序错误时引发的异常。
命名空间:System
程序集:mscorlib(在 mscorlib.dll 中)
[SerializableAttribute] [ComVisibleAttribute(true)] public class ApplicationException : Exception
ApplicationException 由用户程序引发,而不是由公共语言运行库引发。如果打算设计需要创建自己的异常的应用程序,请从 ApplicationException 类派生。ApplicationException 扩展 Exception,但不添加新功能。此异常作为一种区分应用程序定义的异常与系统定义的异常的方法而提供。
ApplicationException 不提供有关异常的原因的信息。大多数情况下都不应引发此类的实例。如果此类被实例化,则描述该错误的可读消息应传递给构造函数。
ApplicationException 使用值为 0x80131600 的 HRESULT COR_E_APPLICATION。
有关 ApplicationException 实例的初始属性值列表,请参见 ApplicationException 构造函数。
下列指南有助于确保正确设计您的自定义异常。
避免使用深的异常层次结构。
有关更多信息,请参见类型和命名空间。
一定要从 System.Exception 或其他常见基本异常之一派生异常。
请注意,捕捉和引发标准异常类型具有一个指南,指出不应从 ApplicationException 派生自定义异常。
异常类名称一定要以后缀 Exception 结尾。
一致的命名约定有助于降低新库的学习曲线。
应使异常可序列化。异常必须可序列化才能跨越应用程序域和远程处理边界正确工作。
有关使类型可序列化的更多信息,请参见序列化。
一定要在所有异常上都提供(至少是这样)下列常见构造函数。确保参数的名称和类型与在下面的代码示例中使用的那些相同。
public class NewException : BaseException, ISerializable { public NewException() { // Add implementation. } public NewException(string message) { // Add implementation. } public NewException(string message, Exception inner) { // Add implementation. } // This constructor is needed for serialization. protected NewException(SerializationInfo info, StreamingContext context) { // Add implementation. } }
一定要只在要求适合的权限后,才通过 System.Object.ToString 的重写报告安全敏感信息。如果权限要求失败,则返回一个不包括安全敏感信息的字符串。
一定要以私有异常状态存储有用的安全敏感信息。请确保只有受信任的代码才能获取该信息。
考虑提供异常属性,以便可以以编程方式访问除消息字符串之外与异常相关的额外信息。
部分版权所有 2005 Microsoft Corporation。保留所有权利。
部分版权所有 Addison-Wesley Corporation。保留所有权利。
有关设计指南的更多信息,请参见 Krzysztof Cwalina 和 Brad Abrams 编著、Addison-Wesley 于 2005 年出版的“Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries”(《框架设计指南:可重用 .NET 库的约定、术语和模式》)。