为什么C#不支持首次通过异常过滤?

时间:2009-03-02 12:00:13

标签: c# vb.net exception finally

注意:这不是a duplicate of Jeff's question

那个问题是“是等同的吗?”我知道没有,我想知道为什么!

我问的原因是我只是清楚它的重要性,结论对我来说似乎很奇怪。

Microsoft企业库的异常处理块建议我们使用此模式:

catch (Exception x)
{
    if (ExceptionPolicy.HandleException(x, ExceptionPolicies.MyPolicy))
        throw;

    // recover from x somehow
}

策略是在XML文件中定义的,这意味着如果客户遇到问题,我们可以修改策略以帮助跟踪问题(或者可能还有问题),以便在我们处理之前快速解决问题适当地 - 这可能涉及与第三方争论,关于谁的错。

这基本上是对一个简单事实的承认,即在没有像这样的设施的情况下,在实际应用中,例外类型的数量及其“可恢复性”状态实际上是不可能管理的。

与此同时,MS的CLR团队表示这不是一个选择,事实证明这些人知道他们在谈论什么!问题是在catch块运行之前,嵌套在finally块内的任何try块都将被执行。因此,这些finally块可能会执行以下任何操作:

  • 无害地修改程序状态(phew,lucky)。
  • 在客户的数据中删除重要的内容,因为程序状态被搞砸了。
  • 伪装或破坏我们需要诊断问题的重要证据 - 特别是如果我们讨论的是对本机代码的调用。
  • 抛出另一个例外,增加了一般的困惑和痛苦。

请注意,using语句和C ++ / CLI析构函数构建在try / finally之上,因此它们也会受到影响。

很明显,用于过滤异常的catch / throw模式并不好。实际需要的是一种通过策略过滤异常而不实际捕获它们从而触发finally块执行的方法,除非我们找到一个告诉我们异常可以安全恢复的策略。

CLR团队最近在博客中发表了这篇文章:

结果是我们必须在VB.NET中编写一个辅助函数,以允许我们从C#访问这个重要的功能。存在问题的一个重要线索就是BCL中有代码可以做到这一点。很多人都写过关于这样做的博客,但他们很少提及关于try / finally块的事情,这是杀手。

我想知道的是:

  • C#团队是否收到过有关此主题的公开声明或直接电子邮件?
  • 是否有任何现有的Microsoft Connect建议要求这样做?我听说过他们的谣言,但没有一个可能的关键词出现了什么。

更新:如上所述,我已经在Microsoft Connect上搜索过而没有找到任何内容。我也(不出所料)谷歌搜索。我只找到了人explaining why they need this feature,或指出advantages of it in VB.NET,或者毫无结果地希望它是added in a future version of C#working around it,而且还有很多misleading advice 。但没有声明从所有当前版本的C#中省略它的理由。我询问现有Connect问题的原因是:(a)我没有创建不必要的副本;(b)我可以告诉感兴趣的人我是否必须创建一个。

更新2:找到an interesting old blog post from Eric Gunnerson,以前是C#团队:

  

“是的,能够制定条件   捕获更方便一些   而不是必须写测试   你自己,但它并没有真正实现   你要做任何新事。“

在我向我正确解释之前,我的假设是一样的!

6 个答案:

答案 0 :(得分:4)

对于任何现有的连接错误。以下问题涉及异常过滤器。用户没有明确说明他们希望它们在执行时的意义上是一个实际的过滤器,但恕我直言的是逻辑所暗示的。

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=401668

除了这个问题,我没有找到或知道与您正在寻找的问题有关的问题。我认为有一个单独的问题明确地调出了对VB.Net样式异常过滤器的需求会很好。

如果您已经做了一些尽职调查以寻找现有问题,我不会过于担心引入重复的问题。如果有嫌疑人,Mads将相应地欺骗它并将您链接到主要请求。

至于从C#团队获得官方回复的部分,当你要么1)提交连接错误或者2)对主要错误进行欺骗时,你可能会得到这个。我真的怀疑现在有正式的理由/理由。

这是关于这个问题的猜测:我的猜测是这个功能根本不在原始的C#1.0功能集上,因为那时候没有足够的需求让它进入语言。 C#和VB团队在每个船舶周期开始时花费了令人难以置信的时间排名语言功能。我们有时必须做出一些非常的难度削减。没有足够的需求,一个功能很少有机会进入语言。

直到最近,我打赌你很难找到10个人中的1个,他们了解VB.Net的Try / When之间的区别,并且只是在C#catch块中使用普通的旧if语句。它最近似乎对人们的思想更多,所以它可能会成为未来版本的语言。

答案 1 :(得分:2)

使用Exception Filter Inject可能比使用委托解决方法更简单。

要真正回答您的问题,您需要Anders Hejlsberg或原设计会议中的人员的回复。你可能会试着看看第9频道的采访者是否可以在下次the C# design team is interviewed时询问。

我猜想,在做出最初决定时,异常过滤器被认为是一种不必要的并发症,可能弊大于利。在本次访谈中,您肯定会看到一种对未经证实的功能保持“沉默”的愿望,即不支持已检查的例外情况:The Trouble with Checked Exceptions

我认为postmoterm诊断方案强烈要求提供对该语言中的异常过滤器的访问。然而,当时可能尚未阐明这些情景。此外,这些场景确实需要适当的工具支持,这在V1中肯定不可用。最后,添加我们没有考虑的这个功能可能会有很大的负面影响。

如果没有连接错误,您应该输入一个并鼓励其他人投票。 [我建议要求访问CLR功能,而不是尝试设计它如何适合该语言。]

答案 2 :(得分:1)

我不相信Java也有过滤选项。猜测如果确实如此,我们也会在C#中看到一个。鉴于VB团队以干净利落的方式开始,VB.net可能有一次机会。

对于在未来版本的C#中获得此选项可能对您有利的一件事是Microsoft声明的目标是在未来版本的C#和VB.net中保持laguage功能之间的平等。我会基于此提出我的论点。

http://www.chriseargle.com/post/2009/01/Parity-Between-Languages.aspx

答案 3 :(得分:0)

关于第一个问题,如果有一个公开声明,那么它很可能会放在网上的某个地方,在这种情况下,谷歌应该出现一些东西(如果存在的话)。

如果它是与C#团队的直接电子邮件,那么它很可能是在NDA下,因此无论如何都无法发布。

关于第二个问题,Microsoft Connect上有一个搜索功能,它们会在输入新建议之前提示您使用。如果找不到,那么可能没有。

我的建议是提出一个建议,然后进行宣传,让别人对此进行权衡。

答案 4 :(得分:0)

据我理解,在重新抛出的那一刻,内部函数中的最终处理程序被执行,这就是为你创造问题的原因。

但是,假设您有一个异常过滤器,可以通过异常而不实际重新抛出异常。你仍然需要以某种方式处理它,你会遇到同样的问题(最终效果)。

因此,除非我误解了某些内容,否则使用语言支持的异常过滤器并没有太大的收获。

答案 5 :(得分:0)

我至少可以想到为什么C#

中缺少异常过滤的两个原因
  1. 允许例外过滤器可能会鼓励程序员在首次通过异常处理期间执行操作,这在当时是不安全的,即使它们可以在'catch'或'finally'中安全地完成。例如,如果“try”块中的代码获取锁并在保持锁定时抛出异常,则在执行外部异常过滤器期间将保持锁定,但将在外部“catch”或“finally”之前释放“阻止运行。此外,至少在我最后一次检查时,异常过滤器中发生的异常并未在其中捕获的内容被默默地扼杀 - 这是一种丑陋的情况。
  2. C#的实施者希望使他们的语言“框架不可知”。如果C#支持.net首次通过异常过滤,那么使用该功能的程序可能无法在不同处理异常的框架上使用。这与C#禁止程序覆盖`Object.Finalize()`的原因相同。虽然围绕`Object.Finalize()`的推理是有缺陷的(正确使用析构函数需要使用其他特定于平台的方法,因此要求使用`Object.Finalize()的析构函数语法`除了t77o之外什么都不会鼓励编写有缺陷的软件)推理确实对异常过滤器有所了解。另一方面,处理该问题的正确方法是暴露一些与异常过滤器相关的功能,即使没有直接暴露异常过滤器。

我真的很想在C#和vb中看到一个功能,它需要使用异常过滤器来实现但不需要直接公开它们,这将是{Exception的可选参数。 1}}阻止。如果没有发生未捕获的异常,则此参数为finally;否则它将保留有问题的例外。这将允许程序在发生异常时想要执行某些操作但实际上不“处理”它的情况。在大多数情况下,除了检查null(意味着该功能等同于公开Exception块)之外,null参数不会用于任何事情,但它会提供优势清理期间发生异常的情况。目前,如果在fault块期间发生异常,则必须扼杀finally - 阻止异常或覆盖预先存在的异常。让finally块代码可用的早期异常使它能够包装或记录它。