我的理解是基于这篇很长但很棒的文章,它支持 C# 规范中列出的行为。
CLI 标准 (ECMA-335) 表明,如果没有合适的捕获,运行时应立即终止。.NET 运行时不这样做,相反,它似乎倾向于 C# 规范 (EMC-334) 的行为。
首先,我觉得奇怪的是语言规范似乎正在定义框架行为。其次,他们似乎自相矛盾。
- 它们是否相互矛盾,还是我理解了文档的错误含义?
- 运行时是否必须以这种方式进行异常处理才能符合标准?
作为一个可选问题,哪一个是“正确”的,例如,如果我要编写自己的 CLI 实现,我应该使用哪一个?请注意,EMCA-335 (CLI) 文档是两个月前更新的,而 EMCA-334 (C#) 是在 2006 年更新的。
ECMA-335 分区 I 第 12.4.2.5 节
- 发生异常时,CLI 会在数组中搜索第一个受保护的块
- 保护包括当前指令指针的区域和
- 是一个 catch 处理程序块并且
- 谁的过滤器希望处理异常
如果在当前方法中未找到匹配项,则搜索调用方法,依此类推。如果未找到匹配项,CLI 将转储堆栈跟踪并中止程序。
如果找到匹配项,CLI 将堆栈返回到刚刚找到的点,但这次调用 finally 和故障处理程序。然后它启动相应的异常处理程序。
C# 规范 §15.9.5 和 §15.10(MSDN 上的§8.9.5 和 §8.10 )
它与 CLI 标准之间的主要区别在于,无论是否找到了 catch 块,应用程序都将不仅存在,而且仍会展开堆栈,并处理 finally 处理程序。
我建议阅读标准本身以更好地理解这一点,因为下面是一个非常粗略的总结。它逐步概述了如何在每种可能的情况下执行 try 语句。
- 在引发异常的函数中:
- 在每个 try 语句中查找匹配的 catch 子句
- 如果存在,则执行 catch 语句
- finally 块如果存在则执行
- 如果没有处理程序,则在调用函数中重复上述步骤
- 如果异常处理终止了当前线程中的所有函数成员调用,表明该线程没有异常处理程序,则该线程本身终止。这种终止的影响是实现定义的。