C#中的异常处理是否与ECMA-335标准相矛盾?

时间:2012-08-28 23:10:45

标签: c# .net exception-handling specifications

我的理解基于this long, but fantastic, article,它支持C#规范中列出的行为。

CLI标准(EMCA-335)显示如果没有合适的catch,运行时应立即终止。 .NET运行时不会这样做,而是倾向于倾向于C#规范(EMCA-334)的行为。

首先,我觉得奇怪的是语言规范似乎是定义框架行为。其次,他们似乎是矛盾的。

  • 他们是否互相矛盾,还是我对文件的含义错误?
  • 运行时是否必须以这种方式处理异常处理以符合标准?

作为一个可选问题,哪一个是“正确的”问题,如果我要编写自己的CLI实现,我应该使用哪一个?请注意,EMCA-335(CLI)文档在两个月前更新,其中EMCA-334(C#)于2006年更新。


ECMA-335 Partition I Section 12.4.2.5

  
      
  • 发生异常时,CLI会在数组中搜索第一个受保护的块   
        
    • 保护包含当前指令指针和
    • 的区域   
    • 是一个catch处理程序块和
    •   
    • 谁的过滤器希望处理异常
    •   
  •   
  • 如果在当前方法中找不到匹配项,则搜索调用方法,依此类推。如果未找到匹配项,CLI将转储堆栈跟踪并中止该程序。

  •   
  • 如果找到匹配项,CLI会将堆栈移回到刚定位的点,但这次调用finally和fault处理程序。然后它启动相应的异常处理程序。

  •   

C# Specification §15.9.5 and §15.10§8.9.5 and §8.10 on MSDN

它与CLI标准之间的主要区别在于,无论是否找到了catch块,应用程序都不会存在,但仍然会解除堆栈,并处理最终的处理程序。

我建议阅读标准本身以获得更好的含义,因为下面是一个非常粗略的总结。它概述了如何在每个可能的场景下执行try语句。

  
      
  • 在引发异常的函数中:   
        
    • 在每个try语句中查找匹配的catch子句   
          
      • 执行catch语句(如果存在)
      •   
    •   
    • 如果存在,则执行finally块
    •   
  •   
  • 如果没有处理程序,则在调用函数
  • 中重复上述步骤   
  • 如果异常处理终止当前线程中的所有函数成员调用,指示该线程没有该异常的处理程序,则该线程本身终止。此类终止的影响是实现定义的。
  •   

3 个答案:

答案 0 :(得分:4)

这里没有冲突。 C#语言规范的措辞如下:

  

如果try语句没有catch子句或者没有catch子句匹配异常:
   •如果try语句有finally块,则执行finally块    •异常传播到下一个封闭的try语句。

Bullet 2特此没有说明当没有下一个封闭的try语句时会发生什么。为此,转到8.9.5结尾:

  

如果异常处理终止当前线程中的所有函数成员调用,指示该线程没有该异常的处理程序,则该线程本身终止。这种终止的影响是实现定义的。

它肯定是实现定义的。除了Ecma 335规范之外,异常处理策略是Microsoft CLR中的可配置项。由ICLRPolicyManager :: SetActionOnFailure()控制。反过来可以使用<legacyUnhandledExceptionPolicy> app.exe.config文件元素在默认主机中进行配置。 CLR版本2.0及更高版本的默认设置是立即终止程序。

这是相当无效的圣经诠释学。对于C#程序员来说,这一切都不应该让人感到意外,特别是考虑到测试它是多么容易。

答案 1 :(得分:3)

我认为这可能只是一个含糊不清的措辞。

  

如果在当前方法中找不到匹配项,则搜索调用方法,依此类推。如果未找到匹配项,CLI将转储堆栈跟踪并中止该程序。

好的,在C#中也是如此。我们都知道,如果我们没有catch,那么例外将会导致我们的计划失效。

  

如果找到匹配项,CLI会将堆栈移回到刚刚找到的位置,但这次调用finally和fault处理程序。然后它启动相应的异常处理程序。

这也符合我们对C#的了解。如果有一些finally(我们没有看到fault)块要处理,当我们从抛出的异常到我们的catch块上升时,它们会被处理,但它停在那里,不再向上移动。

很多关于我们如何阅读“If”开始我引用的第二段摘录。你正在读它“如果......然后......否则没有这样的事情”。它可以被看作是第一个识别堆栈中将要走到的点的摘录:如果有catch,那么它就走到了那一点。如果没有捕获,那么它就会走到堆栈的最顶层,然后我们得到转储并中止。最后的处理程序(和错误处理程序)仍然被调用,但重点不是匹配的catch处理程序。

你的阅读是最直接的,而我的阅读是一个延伸的东西。但是,我的确与同一标准中其他地方finally的描述相匹配,最接近

答案 2 :(得分:0)

O.P.中的cited article有一个不正确的基本假设:

  

当然,如果不首先考虑Windows,我们就无法讨论托管异常   结构化异常处理(SEH)。我们还需要查看C ++异常   模型。那是因为实现了托管异常和C ++异常   在基础SEH机制之上,并且因为托管异常必须   与SEH和C ++异常互操作。

CLR标准(ISO 23271 / ECMA 335)是故意与平台无关的。 Microsoft的实现是许多可能的实现之一(Mono,当然,另一种)。

与Windows结构化异常处理和C ++异常处理的互操作性,我很确定,Microsoft的选择而不是ISO 23271要求。