异常处理(矛盾的文档/最终尝试与使用) [英] Exception handling (contradicting documentation / try-finally vs. using)

查看:57
本文介绍了异常处理(矛盾的文档/最终尝试与使用)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以为我已经了解了C#中的异常处理是如何工作的.重新阅读文档以获得乐趣和自信,我遇到了问题:

I thought I had understood how exception handling in C# works. Re-reading the documentation for fun and self-confidence, I have run into problems:

此文档声称以下两个代码段是等效的,甚至更多,是第一个在编译时转换为第二个.

This document claims that the following two code snippets are equivalent, even more, that the first one is translated to the latter one at compile time.

using (Font font1 = new Font("Arial", 10.0f)) {
  byte charset = font1.GdiCharSet;
}

{
  Font font1 = new Font("Arial", 10.0f);
  try {
    byte charset = font1.GdiCharSet;
  }
  finally {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

此外,它声称:

using语句可确保即使有在对象上调用方法时会发生异常.

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object.

相反,该文档指出:

在已处理的异常内,将保证关联的 finally 块要运行.但是,如果未处理异常,则执行 finally 块取决于异常展开操作的方式触发.

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered.

我不明白这一点.在第一个文档的代码示例中,显然没有处理异常(因为没有catch块).现在,如果第二个文档中的语句为true,则确保 finally 块不能执行.这最终与第一个文档所说的(使用 using 语句确保 ...")矛盾(强调我的意思).

I do not get this together. In the code example from the first document, the exception clearly is unhandled (since there is no catch block). Now, if the statement from the second document is true, the finally block is not guaranteed to execute. This ultimately contradicts what the first document says ("The using statement ensures ...") (emphasis mine).

那真相是什么?

编辑1

我还是不明白.StevieB的答案使我阅读了C#语言规范中的更多内容.在16.3节中,我们有:

I still don't get it. StevieB's answer has made me read more parts from the C# language specification. In section 16.3, we have:

[...]继续搜索,直到找到可以一旦匹配的catch子句被处理,就处理当前的异常[...]找到后,系统准备将控制权转移到第一条语句catch子句的内容.在开始执行catch子句之前,系统首先按顺序执行所有与try语句相关联的嵌套比与try语句相关的嵌套捕获到异常.

[...] This search continues until a catch clause is found that can handle the current exception [...] Once a matching catch clause is found, the system prepares to transfer control to the first statement of the catch clause. Before execution of the catch clause begins, the system first executes, in order, any finally clauses that were associated with try statements more nested that than the one that caught the exception.

因此,我编写了一个简单的测试程序,该程序包含的代码会产生除以零的值,并且位于 try 块中.该异常从未出现在我的任何代码中,但是相应的 try 语句具有一个 finally 块:

So have I made a simple test program which contains code which produces a division by zero and is within a try block. That exception is never caught in any of my code, but the respective try statement has a finally block:

int b = 0;

try {
  int a = 10 / b;
}
finally {
  MessageBox.Show("Hello");
}

最初,根据上面的文档摘要,我曾期望 finally 块永远不会被执行,并且该程序只是在没有连接调试器的情况下执行时才会死掉.但这种情况并非如此;而是显示众所周知的例外对话框",然后显示你好"对话框.

Initially, according to the documentation snippet above, I had expected that the finally block never would be executed and that the program just would die when being executed without a debugger attached. But this is not the case; instead, the "exception dialog box" we all know too well is shown, and after that, the "Hello" dialog box appears.

经过一会儿思考并阅读了文档,文章和类似 ,很明显,对话框"是由内置在Application.Run()中的标准异常处理程序以及可以启动"程序的其他常用方法生成的,因此,我再也不会奇怪为什么 最终块运行.

After thinking a while about that and after having read docs, articles and questions like this and that, it became clear that this "exception dialog box" is produced by a standard exception handler which is built into Application.Run() and the other usual methods which could "start" your program, so I am not wondering any more why the finally block is run.

但是我仍然很困惑,因为在例外对话框"之后的后出现了"Hello"对话框.上面的文档摘要非常清楚(嗯,可能我又太傻了):

But I am still totally baffled because the "Hello" dialog appears after the "exception dialog box". The documentation snippet above is pretty clear (well, probably I am just too silly again):

CLR找不到与 try 语句相关联的 catch 子句,该语句发生零除.因此,它应该将异常向上传递给调用者,在那里也找不到匹配的 catch 子句(那里甚至没有 try 语句),因此(如上所述,我不处理(即捕获)此测试程序中的任何异常).

The CLR won't find a catch clause which is associated with the try statement where the division by zero happens. So it should pass the exception up one level to the caller, won't find a matching catch clause there as well (there is not even a try statement there) and so on (as noted above, I do not handle (i.e. catch) any exception in this test program).

最后,该异常应符合CLR的默认全部捕获异常处理程序(即,默认情况下在Application.Run()及其朋友中处于活动状态的那个处理程序),但是(根据上述文档)CLR现在应执行比默认处理程序嵌套更深的所有 finally 块(不是我的 finally 块属于这些块,不是吗?)之前执行CLR全部捕获默认处理程序的 catch 块.

Finally, the exception should meet the CLR's default catch-all exception handler (i.e. that one which is by default active in Application.Run() and its friends), but (according to the documentation above) the CLR should now execute all finally blocks which are more deeply nested than that default handler ("my" finally block belongs to these, doesn't it?) before executing the CLR catch-all default handler's catch block.

这意味着"Hello"对话框应该出现在例外对话框"之前,不是吗?好吧,显然,这是另一回事.有人可以详细说明吗?

That means that the "Hello" dialog should appear before the "exception dialog box", doesn't it?. Well, obviously, it's the other way around. Could somebody elaborate on that?

推荐答案

该文档声称以下两个代码段是等效的

This document claims that the following two code snippets are equivalent

是.

using语句确保即使在调用对象的方法时发生异常,也会调用Dispose.

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object.

差不多.

这最终与第一份文件所说的相矛盾

This ultimately contradicts what the first document says

嗯,第一个有点太含糊,而不是完全错误.

Well, the first one was being a bit too vague, rather than flat-out incorrect.

在某些情况下,最终将不会运行,包括 using 所暗示的情况.一个 StackOverflowException 就是一个例子(一个真正的溢出堆栈的例子,如果您只是执行 throw new StackOverflowException(),它将最终运行).

There are cases where a finally will not run, including that implied by a using. A StackOverflowException would be one example (a real one from overflowing the stack, if you just do throw new StackOverflowException() the finally will run).

所有示例都是您无法捕获的,并且您的应用程序正在关闭,因此,如果仅在应用程序运行时从 using 进行清理很重要,则 finally 可以.

All the examples are things you can't catch, and your application is going down, so if the clean up from using is only important while the application is running, then finally is fine.

如果即使在程序崩溃时清理仍然至关重要,则 finally 永远是不够的,因为它无法处理例如需要拔出电源插头,在这种情况下,即使在发生事故时也很重要的情况下,拔出电源插头才是必须考虑的情况.

If the clean-up is vital even when the program crashes, then finally can never be enough, as it can't deal with e.g. a power plug being pulled out, which in the sort of cases where clean up is vital even in a crash, is a case that needs to be considered.

在进一步捕获异常并继续执行程序的任何情况下, finally 都将运行.

In any case where the exception is caught further up and the program continues, the finally will run.

对于未捕获的可捕获异常,通常会运行 finally 块,但仍然存在一些异常.一种可能是,如果 try - finally 最终位于终结器中,并且 try 花了很长时间;在终结器队列上等待一段时间后,应用程序将快速失败.

With catchable exceptions that aren't caught, then finally blocks will generally run, but there are still some exceptions. One would be if the try-finally was inside a finaliser and the try took a long time; after a while on the finaliser queue the application will just fail-fast.

这篇关于异常处理(矛盾的文档/最终尝试与使用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆