拿这个代码:
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 块包围了抛出点,并且如果 S 有 finally 块,则控制转移到 finally 块。如果 finally 块抛出另一个异常,则终止当前异常的处理。否则,当控制到达 finally 块的终点时,继续处理当前异常。
- 如果异常处理程序不在当前函数成员调用中,则终止函数成员调用。然后对函数成员的调用者重复上述步骤,并使用与调用函数成员的语句相对应的抛出点。
- 如果异常处理终止了当前线程中的所有函数成员调用,表明该线程没有异常处理程序,则该线程本身终止。这种终止的影响是实现定义的。
我哪里错了?(我有一些自定义控制台错误消息,这是在路上。轻微的,只是烦人,让我质疑语言......)