【发布时间】:2010-10-27 10:56:40
【问题描述】:
获取此代码:
using System;
namespace OddThrow
{
class Program
{
static void Main(string[] args)
{
try
{
throw new Exception("Exception!");
}
finally
{
System.Threading.Thread.Sleep(2500);
Console.Error.WriteLine("I'm dying!");
System.Threading.Thread.Sleep(2500);
}
}
}
}
这给了我这个输出:
Unhandled Exception: System.Exception: Exception!
at OddThrow.Program.Main(String[] args) in C:\Documents and Settings\username
\My Documents\Visual Studio 2008\Projects\OddThrow\OddThrow\Program.cs:line 14
I'm dying!
我的问题是:为什么未处理的异常文本出现在 finally 之前?在我看来,finally 应该在堆栈展开时被执行,甚至在我们知道这个异常未处理之前。请注意对 Sleep() 的调用 - 这些调用发生在 打印未处理的异常之后,就好像它正在执行以下操作一样:
- 未处理的异常文本/消息
- 终于阻止了。
- 终止应用程序
根据 C# 标准,§8.9.5,这种行为是错误的:
- 在当前函数成员中,检查包含抛出点的每个 try 语句。对于每个语句 S,从最内层的 try 语句开始,到最外层的 try 语句结束,评估以下步骤:
- 如果 S 的 try 块包含了抛出点,并且如果 S 有一个或多个 catch 子句,则按出现的顺序检查 catch 子句,以便为异常找到合适的处理程序。指定异常类型或异常类型的基类型的第一个 catch 子句被视为匹配项。一般的 catch 子句(第 8.10 节)被认为是任何异常类型的匹配项。如果找到匹配的 catch 子句,则通过将控制权转移到该 catch 子句的块来完成异常传播。
- 否则,如果 S 的 try 块或 catch 块包围了 throw 点,并且如果 S 有 finally 块,则控制转移到 finally 块。如果 finally 块抛出另一个异常,则终止当前异常的处理。否则,当控制到达 finally 块的终点时,继续处理当前异常。
- 如果在当前函数成员调用中未找到异常处理程序,则终止函数成员调用。然后对函数成员的调用者重复上述步骤,并使用与调用函数成员的语句相对应的抛出点。
- 如果异常处理终止了当前线程中的所有函数成员调用,表明该线程没有异常的处理程序,则该线程本身终止。这种终止的影响是由实现定义的。
我哪里出错了? (我收到了一些自定义控制台错误消息,这是在路上。轻微的,只是烦人,让我质疑语言......)
【问题讨论】:
-
很棒的问题。我会写一篇关于它的博客文章。在此之前,您可能会喜欢阅读以下内容,这些内容将帮助您了解这里发生的事情。这是一个艰难的过程,但值得。 blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx
-
+1 只是因为 Eric Lippert 说这是一个好问题。