|
托管应用中的意外错误
原著:Jason Clark
翻译:Abbey 逆风者
源代码下载:NET0406.exe(122KB,ZIP自解压包)
NET0406IDEAbbey.exe(25KB,rar压缩包)
原文出处:.NET
Column:Unexpected Errors in Managed Applications(MSDN Magazine June 2004)
在本期的 .NET
专栏中,我将介绍一些对付意外错误的技巧。通过捕获异常来处理异常失败是应用程序中常见的做法,对于托管应用程序,当遇到完全没有准备的错误时,我们通常也可以这么做。在理想情况下,你可能会建立一个明确的策略,使应用程序能发现并响应未处理异常、降低的安全许可以及其它有关的边缘情况。但在实际过程中,这些问题常常被忽略。
错误处理底层结构是一个很容易让人迷惑的虚幻的复杂主题。很容易让人陷入到细节当中。所以我会介绍一些相对简单的方法,它们能被广泛地应用于意外错误的处理。
.NET是如何对付未处理异常
公共语言运行时(CLR)具备一套用于管理未处理异常的规则。但如果你正在使用 Windows 窗体类,Windows
窗体消息泵使用其自己的未处理异常策略,它与 CLR 的策略是有所不同。同样,.NET框架作为 ASP.NET
的宿主在对付未处理异常方面也强制执行其自己的标准,由此可见,本文所讨论的这一主题的复杂之处。但不管怎样,在托管应用程序中采取一些慎重的步骤来对付未处理异常是非常重要的。
为了帮助你理解什么是未处理异常,让我们先来简单地看一个能已被处理的异常。Figure 1 中的代码示范了两个方法,其中一个方法调用了另一个方法。
说实话,这段代码有点怪怪的,但它能传达要点。当 MethodA 调用 MethodB 时,MethodB 会抛出一个 InvalidOperationException 类型的异常。这导致正常的执行在
异常被抛出的地方中止,执行引擎在调用堆栈中搜索辅助的 catch 处理例程。因为 MethodA 中有一个 catch子句处理该异常类型,于是执行引擎会在 MethodA 中找到该辅助的 catch 子句并执行它。一旦 catch 块执行完毕,MethodA 继续从 try/catch
语句块后面的代码开始正常运行。这是一个已处理异常的例子,它表示了当调用进入类库和托管代码后大多数托管应用程序
为了响应执行出错而必须实现的异常处理类型。
但是,如果 MethodA 用一个不等于 1 的参数来调用 MethodB,MethodB 则会抛出一个ArgumentException 异常,而 MethodA 并没有提供
这个异常的处理例程。此时,如果在调用堆栈中没有进一步提供 ArgumentException 异常的辅助处理代码,那么这个异常便成为一个未处理异常。
Figure 2 中的代码会抛出一个未处理异常,以响应用户按下其五个按钮中的任一个。每个按钮代表一个能产生未处理异常的不同的线程上下文,为了摸请托管代码响应未处理异常的方式,将 FFigure 2 中的代码编译成一个控制台应用程序,运行它(但不要在调试器模式下运行),然后随便点几个按钮
看看会发生什么情况。
第一次运行这个程序时,它所表现出的行为是令人惊讶的。尤其是当按下底部三个按钮中的任何一个时,你可能注意到这对程序似乎没有任何影响,
即使它们产生了被抛出的未处理异常!在某些情况下,未被处理的异常整个被 CLR 吞食(虽然这种行为在.NET Framework 2.0 中有所改变)。
下面是对该应用程序在执行过程中未处理异常处理器缺省行为的总结:
|