看起来它确实按照一些初步测试,但我想知道的是,如果保证返回,或者在某些情况下它无法返回?这对我的应用程序至关重要,但我还没有找到一个用例,但它不会返回。
我想获得有关这一主题的专业知识。
答案 0 :(得分:34)
其他答案中有许多不准确之处。
当控件离开try块正常时,控制权被传递给finally块 - 也就是说,通过返回,转到,中断,继续或简单地从结束落下来。当控制通过一个被封闭的catch块捕获的异常离开try块时,控制被传递给finally块。
在所有其他情况下,没有保证将调用finally块中的代码。特别是:
如果try块代码进入无限循环,或者线程被冻结并且从未解冻,则永远不会调用finally块代码。
如果进程在调试器中暂停然后被激活地终止,则从不调用finally块。如果进程执行失败快速,则永远不会调用finally块。
如果将电源线拉出墙壁,则永远不会调用finally块。
如果抛出但没有相应的catch块的异常,那么finally块是否运行是运行时的实现细节。当存在未捕获的异常时,运行时可以选择任何行为。 “不运行finally块”和“运行finally块”都是“任何行为”的示例,因此可以选择其中之一。通常,运行时所做的是询问用户是否要在finally块运行之前附加调试器;如果用户说不,则finally块运行。但同样:运行时不是必需来做到这一点。它可能会快速失败。
你不能依赖于始终被调用的finally块。如果你需要强有力的保证代码执行,那么你不应该写一个try-finally,你应该写一个constrained execution region。正确编写CER是C#编程中最困难的任务之一,因此在尝试编写代码之前请仔细研究文档。
顺便提一下,关于最终被封锁的一个“有趣的事实”是:
try { goto X; } finally { throw y; }
X : Console.WriteLine("X");
X是一个无法访问的标签,目标是可访问的goto!所以,下次你参加派对时,你可能会像“大家一样,任何人都可以制作一个C#程序,其中有一个无法访问的标签,目标是可访问的goto?”你会看到派对上谁已经阅读了可达性规范,谁没有阅读!
答案 1 :(得分:12)
无论try或catch块内发生了什么,finally块中的任何内容都将始终执行。如果你从方法中返回它并不重要。
唯一的例外是,如果finally块中的代码抛出异常,那么它将像任何其他代码块一样停止执行。
关于goto,答案仍然是肯定的。请考虑以下代码:
try
{
Console.WriteLine("Inside the Try");
goto MyLabel;
}
finally
{
Console.WriteLine("Inside the Finally");
}
MyLabel:
Console.WriteLine("After the Label");
产生的输出是:
尝试内部
在最后
中标签后
答案 2 :(得分:6)
以下是一些例子:
<强> Environment.FailFast()强>
try
{
Console.WriteLine("Try");
Environment.FailFast("Test Fail");
}
catch (Exception)
{
Console.WriteLine("catch");
}
finally
{
Console.WriteLine("finally");
}
输出只是“尝试”
<强>#1 强>
try
{
Console.WriteLine("Try");
Rec();
}
catch (Exception)
{
Console.WriteLine("catch");
}
finally
{
Console.WriteLine("finally");
}
Rec在哪里:
private static void Rec()
{
Rec();
}
输出仅为“Try”,并且由于StackOverflow,该过程终止。
无歧义的例外
try
{
Console.WriteLine("Try");
throw new Exception();
}
finally
{
Console.WriteLine("finally");
}
答案 3 :(得分:1)
如果发生终止应用程序的致命异常,则不会调用最后一个块。包括堆栈溢出,在调用方法的JIT期间出现异常,致命异常包括CLR运行时。
正如@mintech指出,如果应用程序挂在块中,它根本不会到达finally块。这包括等待同步对象,死锁无限循环甚至是无法关闭它的UI。