一些初始测试,它似乎是这样做的,但我想知道的是它是否保证返回,或者在某些情况下它不能返回?这对我的应用程序至关重要,但我还没有找到它不会返回的用例。
我想获得有关该主题的专业知识。
其他答案中有许多不准确之处。
当控制正常离开 try 块时,控制权将传递给 finally 块 - 即通过返回、转到、中断、继续或只是从末尾掉下来。当控制通过封闭的 catch 块捕获的异常离开 try 块时,控制权将传递给 finally 块。
在所有其他情况下,不能保证最终块中的代码将被调用。特别:
-
如果 try 块代码进入无限循环,或者线程被冻结并且从未解冻,则永远不会调用 finally 块代码。
-
如果进程在调试器中暂停,然后主动终止,则永远不会调用 finally 块。如果进程执行快速故障,则永远不会调用 finally 块。
-
如果电源线从墙上拔出,则永远不会调用最后一个块。
-
如果抛出的异常没有相应的 catch 块,那么 finally 块是否运行是运行时的实现细节。运行时可以在存在未捕获的异常时选择任何行为。"不要运行最终块"和"运行最终块"都是"任何行为"的示例,因此可以选择其中任何一个。通常,运行时所做的是在最终块运行之前询问用户是否要附加调试器;如果用户说"否",则 finally 块运行。但同样:运行时不需要这样做。它可能会很快失败。
你不能依赖总是被调用的最终块。如果您需要对代码执行的有力保证,则不应编写 try-final,而应编写受约束的执行区域。 正确编写 CER 是 C# 编程中最困难的任务之一,因此在尝试编写代码之前请仔细研究文档。
顺便说一句,关于最终被阻止的gotos的一个"有趣的事实"是:
try { goto X; } finally { throw y; }
X : Console.WriteLine("X");
X 是可访问的 goto 定位的无法访问的标签! 因此,下次你参加聚会时,你可以像"嘿大家好,任何人都可以制作一个C#程序,该程序具有可访问的标签,而该标签是可访问的goto的目标吗?"你会看到聚会上谁已经阅读了可访问性规范,谁没有!
在正常情况下,无论 try 或 catch 块内部发生什么,finally 块中的代码都将被执行。您是否从该方法返回并不重要。
在某些情况下,情况并非如此。例如,如果 finally 块中的代码引发异常,那么它将像任何其他代码块一样停止执行。
埃里克·利珀特(Eric Lippert)写了一个更全面的答案,概述了其他案例: https://stackoverflow.com/a/10260233/53777
关于goto,答案仍然是肯定的。请考虑以下代码:
try
{
Console.WriteLine("Inside the Try");
goto MyLabel;
}
finally
{
Console.WriteLine("Inside the Finally");
}
MyLabel:
Console.WriteLine("After the Label");
生成的输出是这样的:
尝试内部
里面终于
标签后
以下是一些示例:
Environment.FailFast()
try
{
Console.WriteLine("Try");
Environment.FailFast("Test Fail");
}
catch (Exception)
{
Console.WriteLine("catch");
}
finally
{
Console.WriteLine("finally");
}
输出只是"尝试"
堆栈溢出
try
{
Console.WriteLine("Try");
Rec();
}
catch (Exception)
{
Console.WriteLine("catch");
}
finally
{
Console.WriteLine("finally");
}
其中 Rec 是:
private static void Rec()
{
Rec();
}
输出仅为"尝试",进程由于堆栈溢出而终止。
未递异常
try
{
Console.WriteLine("Try");
throw new Exception();
}
finally
{
Console.WriteLine("finally");
}
如果出现终止应用程序的致命异常,则不会调用 Final 块。包括堆栈溢出、要调用的方法的 JIT 期间的异常、CLR 运行时的致命异常。
正如@mintech指出的那样,如果应用程序在块内挂起,它根本无法到达最终块。这包括等待同步对象、死锁无限循环,甚至是无法关闭它的 UI。