C# 最终执行时间的定义

C# 最终执行时间的定义,c#,command-line-interface,C#,Command Line Interface,可能的重复项: 表示finally块并不总是运行。那是错误的,对吗 CLI的ECMA标准(C#从中派生其异常功能)规定,在堆栈的两次搜索中处理异常。[13]第一次搜索尝试定位匹配的catch块,如果没有找到,则终止程序。仅当找到匹配的catch块时,才会执行第二个过程,该过程运行中间的finally块。这允许在没有程序状态首先被最终块修改的情况下诊断问题;它还消除了当程序处于未知状态(如外部数据损坏或引发更多异常)时,最终块可能产生不良副作用的风险 但是,我不需要捕获来最终执行: s

可能的重复项:

表示
finally
块并不总是运行。那是错误的,对吗

CLI的ECMA标准(C#从中派生其异常功能)规定,在堆栈的两次搜索中处理异常。[13]第一次搜索尝试定位匹配的catch块,如果没有找到,则终止程序。仅当找到匹配的catch块时,才会执行第二个过程,该过程运行中间的finally块。这允许在没有程序状态首先被最终块修改的情况下诊断问题;它还消除了当程序处于未知状态(如外部数据损坏或引发更多异常)时,最终块可能产生不良副作用的风险

但是,我不需要捕获来最终执行:

    static void Main()
    {
        try { throw new Exception(); }
        finally
        {
            Console.WriteLine("1");
        }
    }

这意味着,如果堆栈上任何地方都没有catch子句,即如果异常未处理,那么异常抛出点处的异常终止是立即的:甚至在可以运行任何finally块之前


有关进一步的讨论和答案,请参阅。

最终声明通常会运行,但正如Dailywtf.com的采访故事()中所指出的,它并不总是运行

我认为(我可能错了),StackOverflowException不会落入finally块。(Dailywtf.com上发布的另一个可爱的例子是一个简单的例子,如果拉电源,finally块将不会运行;))


因此,请注意不要相信它会一直运行。

不要忘记程序集的主方法不是堆栈上的第一个方法。下面还有其他几种方法(托管方法和非托管方法的混合)。这些方法加载正在执行的程序集,最后使用命令行参数调用main方法

在Visual Studio中调试托管应用程序时,典型的调用堆栈如下所示:

MyProgram.exe!MyProgram.Program.Main(string[] args = {string[0]}) Line 15   C#
[Native to Managed Transition]  
[Managed to Native Transition]  
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x3a bytes
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b bytes  
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x66 bytes   
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes   

在这个调用堆栈的某个地方,可能有一个catch处理程序,在用户代码中未处理异常的情况下打印堆栈跟踪。但是,这是一个实现细节,它与的第12.4.2.5节没有冲突。

试试这段代码;最后一个永远不会被称为:

    static void Main()
    {
        try 
        {
            Environment.FailFast("failed");
        }
        finally
        {
            Console.WriteLine("finally!");
        }
    }

我注意到没有人真正回答你的问题,即“这篇文章正确吗?”

不,这是不正确的,因为它遗漏了一个要点

CLI规范中未引用的相关部分是第I部分的第12.4.2节,其中规定:


最后一个处理程序。。。应该是 在块退出时执行, 不管这是否发生在 正常控制流或由未处理的 例外



现在,正如其他人所指出的,这里有一些微妙之处。请注意,规范明确指出,当块退出时,将执行finally。如果程序因故障快速、堆栈溢出或有人将电源线从墙上拔出而终止,则块永远不会退出!程序可能在块退出之前终止,因此finally不会运行。

finally块并不总是运行。考虑将立即终止流程的异常。它被回答了几次,例如这里和这里。您可以通过Constrained Execution Regions(CER).Thx使其可靠,但我知道这一点,我只是认为维基百科的定义是错误的。我不需要catch块来最终阻止executeAFAIK这是唯一一个从未调用finally的情况。@Johannes:StackOverflowException也是候选项。这里永远不会执行finally:
static void Main(string[]args){try{Main(null);}finally{Console.WriteLine(“finally”);}
+1明智而全面的答案,不像许多其他答案那样只关注边缘情况。我想起magicFairyFinally块,它总是运行,即使机器没有电源。谢谢你,埃里克。实际上,我问的是维基百科文本,而不是finally块是否没有执行的情况。PS:你的博客在我的rss列表中,当然是关于C#最好的。也许你不记得了,但我问过你关于把协方差序列翻译成葡萄牙语的事