C#最终执行的时间

Tha*_*tos 21 c# exception finally

拿这个代码:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这给了我这个输出:

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!
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么未处理的异常文本出现在finally之前?在我看来,在我们甚至不知道这个异常未处理之前,最终应该在堆栈展开时被执行.注意对Sleep()的调用 - 这些是在打印出未处理的异常之后发生的,就像它执行以下操作一样:

  1. 未处理的异常文本/消息
  2. 最后块.
  3. 终止申请

根据C#标准,§8.9.5,这种行为是错误的:

  • 在当前函数成员中,将检查包含抛出点的每个try语句.对于每个语句S,从最里面的try语句开始,以最外层的try语句结束,评估以下步骤:
    • 如果S的try块包含抛出点,并且如果S有一个或多个catch子句,则按外观顺序检查catch子句以找到异常的合适处理程序.指定异常类型的第一个catch子句或异常类型的基本类型被视为匹配.一般的catch子句(第8.10节)被认为是任何异常类型的匹配.如果找到匹配的catch子句,则通过将控制转移到该catch子句的块来完成异常传播.
    • 否则,如果try块或S的catch块包含抛出点,并且如果S具有finally块,则控制转移到finally块.如果finally块抛出另一个异常,则终止当前异常的处理.否则,当控制到达finally块的结束点时,继续处理当前异常.
  • 如果当前函数成员调用中未找到异常处理程序,则终止函数成员调用.然后对函数成员的调用者重复上述步骤,其中抛出点对应于调用函数成员的语句.
  • 如果异常处理终止当前线程中的所有函数成员调用,指示该线程没有该异常的处理程序,则该线程本身终止.这种终止的影响是实现定义的.

我哪里错了?(我有一些自定义控制台错误消息,这是在路上.轻微,只是烦人,让我质疑语言......)

kdt*_*kdt 7

标准关于执行顺序的陈述是正确的,并且与您观察的内容不一致.允许"未处理异常"消息出现在进程中的任何位置,因为它只是来自CLR的消息,实际上并不是异常处理程序本身.关于执行顺序的规则仅适用于在CLR内执行的代码,而不适用于CLR本身的代码.

你实际完成的是暴露一个实现细节,即通过查看我们所在的try {}块的堆栈来识别未处理的异常,而不是通过实际探索到root的所有方式.查看此堆栈可能会或可能不会处理异常,但是以这种方式识别未处理的异常.

您可能已经意识到,如果您在main函数中放置了一个顶级try {} catch {},那么您将看到您期望的行为:在检查下一帧的匹配catch之前,最终将执行每个函数{ }.