为什么 C# 不支持首轮异常过滤?
注意:这不是与 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
至于任何现有的连接错误。 以下问题涉及异常过滤器。 用户没有明确声明他们希望它们成为执行时意义上的实际过滤器,但恕我直言,逻辑暗示了这一点。
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.
使用异常过滤器注入可能比使用委托解决方法更简单。
要真正回答您的问题,您需要安德斯·海尔斯伯格(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.]
我也不相信 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
关于第一个问题,如果有公开声明,那么它很可能会放在网络上的某个地方,在这种情况下,谷歌应该会发现一些东西(如果存在的话)。
如果它是直接发送给 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.
据我了解,在重新抛出时,内部函数中的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.
我可以想到 C# 中缺少异常过滤的至少两个原因
我非常希望在 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#
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 afinally
block. This parameter would benull
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, theException
parameter wouldn't be used for anything except to check fornull
(meaning the feature would be equivalent to exposingfault
blocks), but it would offer advantages in cases where an exception occurs during cleanup. Presently, if an exception occurs during afinally
block, it's necessary to either stifle thefinally
-block exception or overwrite the pre-existing one. Having the earlier exception available to thefinally
block code would enable it to either wrap or log it.