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

发布于 2024-07-14 13:07:27 字数 3084 浏览 2 评论 0原文

注意:这不是与 Jeff 的问题重复

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

我之所以问这个问题,是因为我才刚刚明白它的重要性,而这个结论对我来说似乎很奇怪。

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

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

    // recover from x somehow
}

策略是在 XML 文件中定义的,因此这意味着如果客户遇到问题,我们可以修改策略以帮助追踪(或者可能掩盖) )问题给他们一个快速解决方案,直到我们妥善处理为止 - 这可能涉及与第三方争论,这一切都是谁的错。

这基本上是对一个简单事实的承认,即在实际应用程序中,如果没有这样的工具,异常类型的数量及其“可恢复性”状态实际上是不可能管理的。

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

  • 无害地修改程序状态(唷,幸运)。
  • 丢弃客户数据中的重要内容,因为程序状态被搞砸到了未知的程度。
  • 掩盖或销毁我们需要诊断问题的重要证据 - 特别是当我们谈论对本机代码的调用时。
  • 抛出另一个异常,增加了普遍的混乱和痛苦。

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

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

CLR 团队最近在博客中介绍了这一点:

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

我想知道的是:

  • 人们是否从 C# 团队收到过有关此主题的任何公开声明或直接电子邮件?
  • 现有的 Microsoft Connect 建议是否有此要求? 我听说过有关它们的传言,但没有一个可能的关键字出现任何结果。

更新:如上所述,我已经在 Microsoft Connect 上进行了搜索,但没有找到任何内容。 我也(毫不奇怪)谷歌搜索过。 我只发现人们解释为什么他们需要此功能,或指出它的优点在 VB.NET 中,或者徒劳地希望它会是 在 C# 的未来版本中添加,或 解决这个问题,以及大量的 误导性建议。 但没有说明从所有当前版本的 C# 中省略它的理由。 我询问现有 Connect 问题的原因是 (a) 我不会创建不必要的重复项,以及 (b) 我可以告诉感兴趣的人我是否必须创建一个。

更新2:发现一个有趣的旧内容来自前 C# 团队的 Eric Gunnerson 的博客文章:

“是的,能够设定一个条件 一个catch有点方便 而不是必须编写测试 你自己,但它并没有真正启用 你去做任何新的事情。”

这与我的假设相同,直到有人向我正确解释为止!

Note: this is not a duplicate of Jeff's question.

That question asked "Is an equivalent?" I know there isn't, and I want to know why!

The reason I ask is that I've only just become clear on how important it is, and the conclusion seems very strange to me.

The Exception Handling block of Microsoft's Enterprise Library advises us to use this pattern:

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

    // recover from x somehow
}

The policy is defined in an XML file, so that means that if a customer has an issue, we can modify the policy to assist with tracking down (or perhaps papering over) the problem to give them a fast resolution until we deal with it properly - which may involve arguing with 3rd parties, about whose fault it all is.

This is basically an acknowledgement of the simple fact that in real applications the number of exception types and their "recoverability" status is practically impossible to manage without a facility like this.

Meanwhile, the CLR team at MS says this is not an option, and it turns out those guys know what they're talking about! The problem is that right before the catch block runs, any finally blocks nested inside the try block will be executed. So those finally blocks may do any of the following:

  • Harmlessly modify the program state (phew, lucky).
  • Trash something important in the customer's data, because the program state is screwed up to an unknown degree.
  • Disguise or destroy important evidence that we need to diagnose an issue - especially if we're talking about calls into native code.
  • Throw another exception, adding to the general confusion and misery.

Note that the using statement and C++/CLI destructors are built on try/finally, so they're affected too.

So clearly the catch/throw pattern for filtering exceptions is no good. What is actually needed is a way to filter exceptions, via a policy, without actually catching them and so triggering the execution of finally blocks, unless we find a policy that tells us the exception is safe to recover from.

The CLR team blogged about this recently:

The outcome is that we have to write a helper function in VB.NET to allow us to access this vital capability from C#. The big clue that there is a problem is that there is code in the BCL that does this. Lots of people have blogged about doing it, but they rarely if ever mention the thing about try/finally blocks, which is the killer.

What I would like to know is:

  • Are there any public statements or direct emails people have received from the C# team on this subject?
  • Are there any existing Microsoft Connect suggestions asking for this? I've heard rumours of them but none of the likely keywords turned up anything.

Update: as noted above, I have already searched on Microsoft Connect without finding anything. I have also (unsurprisingly) Googled. I've only found people explaining why they need this feature, or pointing out the advantages of it in VB.NET, or fruitlessly hoping that it will be added in a future version of C#, or working around it, And plenty of misleading advice. But no statement on the rationale for omitting it from all current versions of C#. And the reason I'm asking about existing Connect issues is so that (a) I don't create an unnecessary duplicate and (b) I can tell interested people if I have to create one.

Update 2: Found an interesting old blog post from Eric Gunnerson, formerly of the C# team:

"Yes, being able to put a condition on
a catch is somewhat more convenient
than having to write the test
yourself, but it doesn't really enable
you to do anything new."

That was the same assumption I had until it was properly explained to me!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

逆光下的微笑 2024-07-21 13:07:27

至于任何现有的连接错误。 以下问题涉及异常过滤器。 用户没有明确声明他们希望它们成为执行时意义上的实际过滤器,但恕我直言,逻辑暗示了这一点。

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

不过,除了这个问题之外,我找不到或知道没有与您正在寻找的内容相关的问题。 我认为最好有一个单独的问题明确指出需要 VB.Net 样式异常过滤器。

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

至于从 C# 团队获得官方回复的部分,当您 1) 提交连接错误或 2) 因主要错误而被欺骗时,您可能会得到这一信息。 我真的怀疑现在是否有官方原因/理由。

以下是我对这个问题的推测:我的猜测是,这个功能根本就不在最初的 C# 1.0 功能集中,而且从那时起,就没有足够的需求将其纳入该语言中。 C# 和 VB 团队在每个发布周期开始时花费大量时间对语言功能进行排名。 有时我们必须进行一些非常困难的削减。 如果没有足够的需求,某个功能进入该语言的机会就很小。

直到最近,我敢打赌,您很难找到十分之一的人理解 VB.Net 的 Try/When 与在 C# catch 块中使用普通旧式 if 语句之间的区别。 最近它似乎更受人们关注,所以也许它会成为该语言的未来版本。

As to any existing connect bugs. The following issue deals with exception fliters. The user did not explicitly state they wanted them be an actual filter in the sense of when they execute but IMHO it's implied by the logic.

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

Besides that issue though, there are no issues I can find or know of that are related to what you are looking for. I think it would do good to have a separate issue which explicitly calls out the want for VB.Net style exception filters.

I wouldn't worry too much about introducing a duplicate question if you've done a bit of due diligence looking for an existing one. If there is a dupe, Mads will dupe it accordingly and link you to the main request.

As for the part of getting an official response from the C# team, you will likely get that when you either 1) file a connect bug or 2) get duped against the main bug. I really doubt there is an official reason / justification out there right now.

Here's my speculation on the issue: My guess is that this feature simply wasn't on the original C# 1.0 feature set and since that time there hasn't been enough demand to make it into the language. The C# and VB team spend an unbelievable amount of time ranking language features at the start of every ship cycle. We have to make some very difficult cuts at times. Without sufficient demand there is very little chance a feature will make it into the language.

Up until recently I bet you would be hard pressed to find 1 out of 10 people who understood the difference between VB.Net's Try/When and just using a plain old if statement in a C# catch block. It seems to be a bit more on peoples minds lately so maybe it will make it into a future version of the langauge.

楠木可依 2024-07-21 13:07:27

使用异常过滤器注入可能比使用委托解决方法更简单。

要真正回答您的问题,您需要安德斯·海尔斯伯格(Anders Hejlsberg)或参加原始设计会议的人的答复。 您可以尝试看看下次是否可以得到第 9 频道面试官的询问 C#设计团队接受采访

我猜想,当做出最初的决定时,异常过滤器被视为一种不必要的复杂化,可能弊大于利。 在这次采访中,您当然可以看到对不支持检查异常的决定对未经证实的功能保持“沉默”的愿望:检查异常的麻烦

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

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

Using Exception Filter Inject may be simpler than using the delegate workaround.

For a real answer to your question you will need a response from Anders Hejlsberg, or someone who was in the original design meetings. You might try seeing if you can get it asked by the Channel 9 interviewer next time the C# design team is interviewed.

I'd guess that when the original decision was made, exception filters were seen as an unnecessary complication that might do more harm than good. You can certainly see a desire to remain 'silent' about unproven features in this interview about the decision not to support checked exceptions: The Trouble with Checked Exceptions
.

I think the postmoterm diagnostic scenarios argue strongly for providing access to exception filters in the language. However those scenarios may not have been articulated at the time. Also those scenarios really need proper tooling support, which certainly wasn't available in V1. Finally there may be big negatives about adding this feature that we are not considering.

If there isn't a connect bug on this you should enter one and encourage others to vote it up. [I'd recommend asking for access to the CLR feature rather than attempting to design how it fits in the language.]

篱下浅笙歌 2024-07-21 13:07:27

我也不相信 Java 有过滤器选项。 猜测如果确实如此,我们也会在 C# 中看到它。 鉴于 VB 团队是从零开始的,VB.net 很可能有一个偶然。

在 C# 的未来版本中获得此选项可能对您有利的一件事是 Microsoft 的既定目标,即在 C# 和 VB.net 的未来版本中保持语言功能之间的平等。 我将在此基础上提出我的论点。

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

I don't believe that Java has a filter option either. Guessing that if it did, we would also see one in C#. VB.net likely has one by chance given that the VB team started with a clean slate.

One thing that might work in your favor as far as gaining this option in a future version of C# is Microsoft's stated goal to maintain parity between laguage features in future versions of C# and VB.net. I would put forward my arguement based on that.

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

不如归去 2024-07-21 13:07:27

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

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

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

我的建议是提出建议,然后进行推广,让其他人参与进来。

In regards to the first question, if there was a public statement, then it was more than likely put on the web somewhere, in which case, Google should turn up something (if it exists).

If it is a direct email with the C# team, then it is more than likely that it is under NDA, so it wouldn't be able to be published anyways.

With the second question, there is a search capability on Microsoft Connect which they prompt you to use before entering a new suggestion. If you can't find it, then there probably isn't one.

My recommendation would be to put a suggestion in, and then promote it to get others to weigh in on it.

放飞的风筝 2024-07-21 13:07:27

据我了解,在重新抛出时,内部函数中的finally处理程序被执行,这就是给你带来问题的原因。

但是,假设您有一个异常过滤器,它可以传递异常而不实际重新抛出异常。 您仍然必须在某个地方以某种方式处理它,并且您将在那里遇到相同类型的问题(最终效果)。

因此,除非我误解了某些内容,否则使用语言支持的异常过滤器不会带来很大的好处。

As I understand them, at the moment of rethrow, the finally handlers in the inner functions are executed and that's what creates problems for you.

But let's say you have an exception filter that passes the exception through without actually rethrowing it. You'll still have to handle it somehow somewhere, and you will run in the same kinds of problems (finally effects) there.

So unless I am misunderstanding something, there is not great gain from having language-supported exception filters.

烧了回忆取暖 2024-07-21 13:07:27

我可以想到 C# 中缺少异常过滤的至少两个原因

  1. 允许异常过滤器可能会鼓励程序员在第一遍异常处理期间做一些当时不安全的事情,即使它们可以在“catch”中安全地完成或“终于”。 例如,如果“try”块中的代码获取锁并在持有锁时抛出异常,则该锁将在外部异常过滤器执行期间被持有,但将在外部“catch”或“finally”之前释放“块已运行。 另外,至少在我上次检查时,异常过滤器中发生的异常但未被捕获的异常被默默地抑制了——这是一种丑陋的情况。
  2. C# 的实现者的愿景是让他们的语言“与框架无关”。 如果 C# 支持 .net 首次通过异常过滤,则使用该功能的程序可能无法在以不同方式处理异常的框架上使用。 这与 C# 禁止程序重写“Object.Finalize()”的原因相同。 虽然围绕“Object.Finalize()”的推理是有缺陷的(正确使用析构函数需要使用其他特定于平台的方法,因此要求“Object.Finalize()”使用析构函数语法除了 t77o 鼓励编写有缺陷的软件)对于异常过滤器的推理确实有一定道理。 另一方面,处理该问题的正确方法是公开一些与异常过滤器相关的功能,即使不直接公开异常过滤器也是如此。

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

I can think of at least two reasons why exception filtering is absent from C#

  1. Allowing exception filters might encourage programmers to do things during first-pass exception handling which would be unsafe at that time, even though they could be done safely within a 'catch' or 'finally'. For example, if code within the "try" block acquires a lock and throws an exception while the lock is held, the lock will be held during the execution of outer exception filters, but will be released before an outer "catch" or "finally" block is run. Also, at least the last time I checked, exceptions that occurred within an exception filter and not caught within it were silently stifled--something of an ugly situation.
  2. The implementers of C# have a vision of making their language 'framework agnostic'. If C# supported .net first-pass exception filtering, programs which used that feature might be unusable on frameworks which handle exceptions differently. This is the same reason that C# forbids programs from overriding `Object.Finalize()`. While the reasoning surrounding `Object.Finalize()` is flawed (correct use of destructors requires use of other platform-specific methods, so requiring the use of destructor syntax for `Object.Finalize()` accomplishes nothing except t77o encourage the writing of defective software) the reasoning does make some sense with regard to exception filters. On the other hand, the proper way to deal with that issue would be to expose some exception-filter-related features even if one didn't expose exception filters directly.

One feature I'd really like to see in C# and vb, which would require the use of exception filters to implement but which would not require exposing them directly, would be an optional Exception parameter for a finally block. This parameter would be null if no uncaught exception occurs; otherwise it would hold the exception in question. This would allow for situations where a program will want to do something when an exception occurs, but not actually "handle" it. In most cases, the Exception parameter wouldn't be used for anything except to check for null (meaning the feature would be equivalent to exposing fault blocks), but it would offer advantages in cases where an exception occurs during cleanup. Presently, if an exception occurs during a finally block, it's necessary to either stifle the finally-block exception or overwrite the pre-existing one. Having the earlier exception available to the finally block code would enable it to either wrap or log it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文