C#最终执行时间

C#最终执行时间,c#,exception,finally,C#,Exception,Finally,以这个代码为例: using System; namespace OddThrow { class Program { static void Main(string[] args) { try { throw new Exception("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);
            }
        }
    }
}
这给了我这个输出:

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语句。对于每个语句,从最内层的try语句开始,到最外层的try语句结束,将计算以下步骤:
      • 如果S的try块包含抛出点,并且S有一个或多个catch子句,则将按外观顺序检查catch子句,以找到适合异常的处理程序。指定异常类型或异常类型的基类型的第一个catch子句被视为匹配。一般捕获条款(§8.10)被视为与任何例外类型相匹配。如果找到了匹配的catch子句,则通过将控制权转移到该catch子句的块来完成异常传播
      • 否则,如果S的try块或catch块包含抛出点,并且S有finally块,则控制权转移到finally块。如果finally块引发另一个异常,则终止当前异常的处理。否则,当控件到达finally块的端点时,将继续处理当前异常
    • 如果异常处理程序未位于当前函数成员调用中,则函数成员调用将终止。然后对函数成员的调用方重复上述步骤,抛出点对应于调用函数成员的语句
    • 如果异常处理终止当前线程中的所有函数成员调用,表明该线程没有异常处理程序,则该线程本身终止。此类终止的影响由实施定义

    我哪里做错了?(我有一些自定义的控制台错误消息,这是一个障碍。轻微的,只是令人讨厌,让我对语言产生疑问…

    如果在某个点被捕获,try-catch-finally块的工作与您预期的完全一样。当我为此编写一个测试程序时,我使用了各种嵌套级别,它的行为方式与您所描述的方式相匹配的唯一情况是,异常完全没有被代码处理,并且冒泡到操作系统中

    每次我运行它时,都是操作系统创建了错误消息。 所以问题不在于C#,而在于未经用户代码处理的错误不再在应用程序的控制之下,因此运行时(我相信)无法对其强制执行模式

    如果您创建了一个windows窗体应用程序,并将所有消息写入一个文本框(然后立即刷新),而不是直接写入控制台,那么您根本不会看到该错误消息,因为它是由调用应用程序插入错误控制台的,而不是由您自己的代码插入的

    编辑


    我将努力强调其中的关键部分。未处理的异常超出您的控制范围,您无法确定何时执行它们的异常处理程序。如果您在应用程序中的某个点捕获到异常,那么
    finally
    块将在堆栈中较低的
    catch
    块之前执行。

    我读取内容的方式可能会偏离基准……但是您有一个try finally块,而没有catch


    根据您发布的描述,由于从未捕获异常,因此它会冒泡到调用方,在堆栈中运行,最终未处理,调用终止,然后调用finally块。

    输出实际上来自默认的CLR异常处理程序。异常处理程序发生在finally块之前。在finally块之后,CLR由于未处理的异常而终止(它不能在之前终止,因为c#保证[1]调用finally子句)

    所以我想说这只是标准行为,异常处理在最终发生之前就发生了


    [1] 保证在正常运行期间,至少在没有内部运行时错误或断电的情况下,try/finally不带catch将使用默认的处理程序,该处理程序会完全按照您看到的执行。我一直都在使用它,例如,在处理异常时会覆盖一个错误,但仍然需要进行一些清理的情况下


    还请记住,标准错误和标准输出的输出是缓冲的。

    虽然不是完全预期的,但程序确实按其应有的方式运行。finally块不应首先运行,而应始终运行

    我调整了你的样品:

    public static void Main()
    {
        try
        {
            Console.WriteLine("Before throwing");
            throw new Exception("Exception!");
        }
        finally
        {
            Console.WriteLine("In finally");
            Console.ReadLine();
        }
    }
    

    在这种情况下,您将得到讨厌的未处理异常对话框,但之后控制台将输出并等待输入,从而执行最后的,而不是之前的Windows本身捕获未处理的异常。

    < P>在混合中添加更多,请考虑如下:

    using System;
    namespace OddThrow
    {
        class Program
        {
            static void Main()
            {
                AppDomain.CurrentDomain.UnhandledException +=
                    delegate(object sender, UnhandledExceptionEventArgs e)
                {
                    Console.Out.WriteLine("In AppDomain.UnhandledException");
                };
                try
                {
                    throw new Exception("Exception!");
                }
                catch
                {
                    Console.Error.WriteLine("In catch");
                    throw;
                }
                finally
                {
                    Console.Error.WriteLine("In finally");
                }
            }
        }
    }
    
    在我的系统(挪威语)上显示:

    [C:\..] ConsoleApplication5.exe
    In catch
    In AppDomain.UnhandledException
    
    Ubehandlet unntak: System.Exception: Exception!
       ved OddThrow.Program.Main() i ..\Program.cs:linje 24
    In finally
    

    本标准关于执行顺序的陈述是正确的,并且与您所观察到的内容不一致。“未处理的异常”消息允许出现在流程中的任何点,因为它只是来自CLR的消息,而不是异常处理程序本身。关于执行顺序的规则仅适用于CLR内部执行的代码,而不适用于CLR本身的功能

    实际上,您所做的是公开一个实现