【发布时间】:2017-07-04 04:26:16
【问题描述】:
我以为我已经了解 C# 中的异常处理是如何工作的。重新阅读文档以获得乐趣和自信,我遇到了问题:
This document 声称以下两个代码 sn-ps 是等价的,甚至更多的是,第一个在编译时被翻译成后一个。
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 语句确保 Dispose 被调用,即使 在对象上调用方法时发生异常。
相比之下,that document 声明:
在处理的异常中,保证关联的
finally块 要运行。但是,如果异常未处理,则执行finally块取决于异常展开操作的方式 触发。
我没有把它放在一起。在第一个文档的代码示例中,异常显然是未处理的(因为没有 catch 块)。现在,如果第二个文档中的语句为真,则finally 块不保证执行。这最终与第一个文件所说的相矛盾(“using 声明确保 ...”)(强调我的)。
那么真相是什么?
编辑 1
我还是不明白。 StevieB 的回答让我阅读了 C# 语言规范中的更多部分。在第 16.3 节中,我们有:
[...] 这个搜索一直持续到找到一个 catch 子句可以 处理当前异常 [...] 一旦匹配的 catch 子句 发现,系统准备将控制权转移到第一条语句 的 catch 子句。在 catch 子句开始执行之前, 系统首先按顺序执行任何 finally 子句 与 try 语句相关联的嵌套比 捕获了异常。
所以我制作了一个简单的测试程序,其中包含产生除以零的代码,并且位于try 块内。我的任何代码中都不会捕获该异常,但相应的 try 语句有一个 finally 块:
int b = 0;
try {
int a = 10 / b;
}
finally {
MessageBox.Show("Hello");
}
最初,根据上面的文档 sn-p,我曾预计 finally 块永远不会被执行,并且程序在没有附加调试器的情况下执行时会死掉。但这种情况并非如此;而是显示了我们都非常熟悉的“异常对话框”,然后出现了“Hello”对话框。
在考虑了一段时间并阅读了文档、文章和诸如this 和that 之类的问题之后,很明显,这个“异常对话框”是由内置于 Application 的标准异常处理程序产生的。 Run() 和其他可以“启动”你的程序的常用方法,所以我不再想知道 为什么finally 块会运行。
但我仍然完全感到困惑,因为“Hello”对话框出现在“异常对话框”之后。上面的文档 sn-p 很清楚(好吧,可能我又太傻了):
CLR 找不到与发生被零除的try 语句关联的catch 子句。所以它应该将异常向上一级传递给调用者,在那里也找不到匹配的catch 子句(那里甚至没有try 语句)等等(如上所述,我不处理(即捕获)此测试程序中的任何异常)。
最后,异常应该满足 CLR 的默认捕获所有异常处理程序(即默认情况下在 Application.Run() 及其朋友中处于活动状态的异常处理程序),但是(根据上面的文档)CLR 现在应该执行所有finally 块嵌套比默认处理程序更深(“我的”finally 块属于这些,不是吗?)在执行 CLR 捕获所有默认处理程序的 @987654345 @块。
这意味着“Hello”对话框应该出现在“异常对话框”之前,不是吗?嗯,很明显,情况正好相反。有人可以详细说明一下吗?
【问题讨论】:
-
有点不清楚你在问什么。您基本上是在问
using是否会 100% 处理?因为如果是这样,你是对的,不,它不会(必然)因为它受到在它“包含”的代码期间引发的那种异常的影响,类似于你可能更熟悉的try catch. -
我相信“未处理”是指应用程序未处理异常,即异常将导致应用程序结束/崩溃。由于应用程序正在终止,因此不一定需要执行 finally 块。
-
@JᴀʏMᴇᴇ:我猜他是在问
finally是否有可能不会在未处理的异常上执行,或者 异常展开操作 是什么意思。 MSDN 中的链接 Unhandled Exception Processing in the CLR 已失效 -
"... 异常显然未处理..." - 仅在 那个 代码块中。在调用堆栈的上层可以有
catch块。 -
@JᴀʏMᴇᴇ 我在问哪个文件是正确的。显然,其中一个肯定是错的,除非我已经失去了我内心的其余逻辑思维......
标签: c# exception try-catch using