如果我退出C#中的try / finally块,那么finally中的代码总会运行吗?

它看起来像是根据一些初步测试,但我想知道的是,如果它保证返回或在某些情况下它不能返回? 这对我的应用程序至关重要,但我还没有找到一个用例但它不会返回。
我想获得有关这一主题的专业知识。

无论try或catch块内发生了什么,finally块中的任何内容都将始终执行。 如果您返回表单方法并不重要。

唯一的例外是如果finally块中的代码抛出exception,那么它将像任何其他代码块一样停止执行。

关于goto,答案仍然是肯定的。 请考虑以下代码:

try { Console.WriteLine("Inside the Try"); goto MyLabel; } finally { Console.WriteLine("Inside the Finally"); } MyLabel: Console.WriteLine("After the Label"); 

产生的输出是这样的:

试试里面

在最后

标签之后

其他答案中有许多不准确之处。

当控制正常地离开try块时,控制被传递给finally块 – 也就是说,通过返回,转到,中断,继续或简单地从结束掉落。 当控制通过一个被封闭的catch块捕获的exception离开try块时,控制被传递给finally

在其他所有情况下,都无法保证将调用finally块中的代码。 特别是:

  • 如果try块代码进入无限循环,或者线程被冻结并且从未解冻,则永远不会调用finally块代码。

  • 如果进程在调试器中暂停然后被激活地终止,则从不调用finally块。 如果进程执行失败快速,则永远不会调用finally块。

  • 如果将电源线拉出墙壁,则永远不会调用finally块。

  • 如果抛出没有相应catch块的exception,那么finally块是否运行是运行时的实现细节 。 当存在未捕获的exception时,运行时可以选择任何行为。 “不运行finally块”和“运行finally块”都是“任何行为”的示例,因此可以选择其中之一。 通常,运行时所做的是询问用户是否要在finally块运行之前附加调试器; 如果用户说不,则finally块运行。 但同样:运行时不需要这样做。 它可能会快速失败。

你不能依赖于始终被调用的finally块。 如果您需要强有力的保证代码执行,那么您不应该编写try-finally,您应该编写一个约束执行区域 。 正确编写CER是C#编程中最困难的任务之一,因此在尝试编写代码之前,请仔细研究文档。

顺便说一句,关于最终封锁的getos的“有趣事实”是:

 try { goto X; } finally { throw y; } X : Console.WriteLine("X"); 

X是一个无法访问的标签,目标是可访问的goto! 所以,下次你参加派对时,你可以像“大家一样,任何人都可以制作一个C#程序,其中有一个无法访问的标签,目标是可访问的goto?” 你会看到派对上谁已经阅读了可达性规范,谁没有阅读!

这里有些例子:

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”,并且由于StackOverflow,进程终止。

无耻的例外

  try { Console.WriteLine("Try"); throw new Exception(); } finally { Console.WriteLine("finally"); } 

如果终止应用程序的致命exception,则不会调用最后一个块。 包括堆栈溢出,在JIT调用方法期间的exception,致命exception包括CLR运行时。

正如@mintech指出,如果应用程序挂在块内,它根本不会到达finally块。 这包括等待同步对象,死锁无限循环甚至无法关闭它的UI。