0

可能的重复:
finally 不在 .net try..finally 块中执行的条件
在 C# 中,如果抛出未处理的异常,finally 块是否会在 try、catch、finally 中执行?

http://en.wikipedia.org/wiki/Comparison_of_C_Sharp_and_Java#Finally_Blocks_and_Uncaught_Exceptions指出该finally块并不总是运行。那是错误的,对吧?

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

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

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

5 回答 5

7

我注意到没有人真正回答您的问题,即“这段文字是否正确?”

不,这是不正确的,因为它忽略了一个重要的点。

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


finally 处理程序 ... 应在块退出时执行,无论是由正常控制流发生还是由未处理的异常发生。


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

于 2010-01-12T17:36:31.270 回答
1

试试这个代码;finally 永远不会被调用:

    static void Main()
    {
        try 
        {
            Environment.FailFast("failed");
        }
        finally
        {
            Console.WriteLine("finally!");
        }
    }
于 2010-01-12T12:43:07.883 回答
0

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

有关进一步的讨论和答案,请参阅C# Time of finally execution

于 2010-01-12T11:31:42.687 回答
0

finally 语句通常会运行,但正如(据我所知)TheDailyWTF.com 的采访故事之一(http://thedailywtf.com/Articles/My-Tales.aspx)中指出的那样,它并不总是运行。

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

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

于 2010-01-12T11:43:49.807 回答
0

不要忘记程序集的 main 方法不是堆栈中的第一个方法。下面还有其他几种方法(托管和非托管方法的混合)。这些方法加载您正在执行的程序集,最后使用命令行参数调用 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 节不冲突。

于 2010-01-12T12:11:40.313 回答