我的理解是基于这篇很长但很棒的文章,它支持C#规范中列出的行为。
CLI标准(EMCA-335)表明,如果没有合适的捕获,运行时应该立即终止。.NET运行时没有这样做,相反,它似乎倾向于C#规范(EMCA-334)的行为。
首先,我觉得奇怪的是,语言规范似乎定义了框架行为。第二,它们似乎自相矛盾。
作为一个可选的问题,哪一个是“正确的”问题,比如,如果我要编写我自己的CLI实现,我应该使用哪一个?注意,EMCA-335 (CLI)文档是两个月前更新的,其中EMCA-334 (C#)是在2006年更新的。
C#规范第15.9.5和15.10节 (关于MSDN的§8.9.5和§8.10)
它与CLI标准的主要区别在于,无论是否找到了catch块,应用程序不仅存在,而且仍然会展开堆栈,并处理最后的处理程序。
我建议阅读标准本身,以获得更好的含义,因为以下是一个非常粗略的总结。它一步一步地概述了如何在每个可能的场景中执行try语句。
- A finally block is executed if it exists
发布于 2012-08-28 16:26:28
我认为这可能只是一个含糊的措辞问题。
如果在当前方法中找不到匹配,则搜索调用方法,以此类推。如果没有找到匹配项,CLI将转储堆栈跟踪并中止程序。
好吧,在C#中是这样的。我们都知道,如果我们没有一个catch
,那么一个异常将使我们的程序瘫痪。
如果找到匹配,则CLI将堆栈送回刚才定位的点,但这次调用finally和故障处理程序。然后启动相应的异常处理程序。
这也符合我们对C#的了解。如果有一些finally
(我们没有看到fault
)块,当我们从抛出的异常上升到catch
块时,这些块将被处理,但是它们会在那里停止,不会在堆栈上继续运行。
很大程度上取决于我们如何阅读“如果”,它开始了我刚才引用的第二节。你读起来就像“如果.那么.否则就不会有这样的事情了”。但是,它可以读为识别堆栈中将被移动到的点的第一个摘录:如果有一个catch
,那么它已经走到了那个点。如果没有捕获,那么它就会走到堆栈的最顶端,然后我们得到一个转储和中止。最终处理程序(和故障处理程序)仍然被调用,但重点不是匹配的catch处理程序。
你的阅读是最直截了当的,而我的则是把事情拉得有点长的。然而,在同一标准的其他地方,我的描述与finally
的描述非常接近。
发布于 2012-08-28 16:13:33
这里没有冲突。C#语言规范的措辞如下:
如果try语句没有catch子句,或者没有catch子句匹配异常: 如果try语句有一个finally块,那么执行finally块。 异常被传播到下一个包含try语句的容器中。
这里的项目2没有特别说明在没有下一个包含try语句的情况下会发生什么。为此,请转到8.9.5结尾:
如果异常处理终止当前线程中的所有函数成员调用(指示线程没有异常处理程序),则线程本身将终止。这种终止的影响是由执行定义的。
当然,它是由实现定义的。除了Ecma 335规范之外,异常处理策略是Microsoft中的一个可配置项。由ICLRPolicyManager::SetActionOnFailure()控制。然后,使用<legacyUnhandledExceptionPolicy>
app.exe.config文件元素在默认主机中进行配置。CLRVersion2.0和更高版本的默认设置是立即终止程序。
否则,这是相当无效的圣经解释学。所有这些都不应该让C#程序员感到惊讶,特别是考虑到测试是多么容易。
发布于 2012-08-28 18:38:04
O.P.中的被引用文章有一个错误的基本假设:
当然,如果不首先考虑Windows结构化异常处理(SEH),我们就不能谈论托管异常。我们还需要查看C++异常模型。这是因为托管异常和C++异常都是在底层SEH机制之上实现的,而且托管异常必须与SEH和C++异常互操作。
CLR标准(ISO 23271/ECMA 335)有意与平台无关。Microsoft的实现是许多可能的实现之一(当然,Mono是另一个实现)。
我敢肯定,与Windows结构化异常处理和C++异常处理的互操作性是微软的选择,而不是ISO 23271的要求。
https://stackoverflow.com/questions/12168825
复制