C # “ finally”块是否始终执行?

可能的复制品:
如果返回一个 Tryblock 中的值,是否会触发 Finally 语句中的代码?

考虑下面的代码 C # 代码。“ finally”块是否执行?

public void DoesThisExecute() {
string ext = "xlsx";
string message = string.Empty;
try {
switch (ext) {
case "xls": message = "Great choice!"; break;
case "csv": message = "Better choice!"; break;
case "exe": message = "Do not try to break me!"; break;
default:
message = "You will not win!";
return;
}
}
catch (Exception) {
// Handle an exception.
}
finally {
MessageBox.Show(message);
}
}

哈,在我写完这个之后,我意识到我可以在 Visual Studio 中自己测试这个。不过,请随意回答!

93278 次浏览

简单的回答是的。但是规则中也有一些“例外”。

是的,finally总是执行,现在不管 finally 块中的代码是否会导致异常,情况就不同了。

来自 MSDN Try-finally (C # Reference)

Finally 块对于 清理分配给 Try 块以及运行 必须执行的代码 控件总是 传递给 finally 块 Try 块如何退出 .

是的,在正常情况下(正如许多人指出的那样)。

Finally 块对于 清理分配给 Try 块以及运行 必须执行的代码 是一个例外。控制总是 传递给 finally 块 Try 块如何退出。

而渔获物是用来处理 语句中发生的异常 块,最后用于保证一个 执行代码的语句块 不管前面的尝试如何 街区已经出来了。

Http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx

从 MSDN C # 规范的 try语句:

当 control 离开 try语句时,始终执行 finally块的语句。无论控制转移是正常执行的结果,还是执行 breakcontinuegotoreturn语句的结果,或者是从 try语句传播异常的结果,都是如此。

来源

有些情况下 finally 块不会执行:

  1. 环境,快速失效
  2. 无法捕捉的异常类型
  3. 停电

不,没有。如果应用程序仍在运行,它将始终执行(除了在 FastFail异常、 MSDN 链路期间,如其他异常所示)。它将在退出块的 try/catch 部分时执行。

如果应用程序崩溃,它将不会执行: 通过 kill process 命令等被杀死。这一点非常重要,因为如果您编写的代码绝对期望它运行,比如手动执行回滚,如果没有其他方法,它将自动提交,那么您可能会遇到应用程序在此之前中止的场景。老实说,这是一个外部场景,但是在这些情况下注意这一点很重要。

正确答案是,是的。

尝试调试您的程序,并放置一个断点,然后观察控件是否仍然命中 finally 块。

不,不是的。

只有一种方法可以绕过它,那就是 Environment.FailFast()。见 http://msdn.microsoft.com/de-de/library/ms131100.aspx。在其他任何情况下,都保证终结器得到执行; -)

False Fast 方法写入消息 字符串添加到 Windows 应用程序 事件日志,创建一个转储 应用程序,然后终止 消息字符串为 也包括在错误报告中 微软。

方法,而不是使用 退出方法以终止您的 应用程序,如果您的 申请书已损坏,无法修复, 并执行您的应用程序的 Try/finally 块和终结器将 腐败的程序资源。

finally总是被执行的说法并不完全正确。参见 被黑了中的 这个答案:

有两种可能:

  • StackOverflowException
  • ExecutingEngineException

将不执行 finally 块 当有一个 StackOverflow 异常时 因为堆栈上没有空间 甚至执行更多的代码。它会 也不会被调用 执行工程异常,即 非常罕见。

实际上,对于任何类型的异步异常(如 StackOverflowExceptionOutOfMemoryExceptionThreadAbortException) ,都不能保证 finally块的执行。

但是,这些异常是您通常无法恢复的异常,并且在大多数情况下您的流程将退出。

事实上,至少还有另外一种情况,即 finally没有像 Brian Rasmussen在现在的 被删除的问题中描述的那样执行:

我知道的另一种情况是 终结器抛出一个异常 如果进程终止 因此 保证不适用。

下面的代码说明了这个问题

static void Main(string[] args) {
try {
DisposableType d = new DisposableType();
d.Dispose();
d = null;
GC.Collect();
GC.WaitForPendingFinalizers();
} catch {
Console.WriteLine("catch");
} finally {
Console.WriteLine("finally");
}
}


public class DisposableType : IDisposable {
public void Dispose() {
}


~DisposableType() {
throw new NotImplementedException();
}
}

一个可靠的 try/catch/finally 必须使用 约束执行区域(CER):

[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
public IntPtr m_outputHandle;
}


sealed class MySafeHandle : SafeHandle
{
// Called by P/Invoke when returning SafeHandles
public MySafeHandle()
: base(IntPtr.Zero, true)
{
}


public MySafeHandle AllocateHandle()
{
// Allocate SafeHandle first to avoid failure later.
MySafeHandle sh = new MySafeHandle();


RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
MyStruct myStruct = new MyStruct();
NativeAllocateHandle(ref myStruct);
sh.SetHandle(myStruct.m_outputHandle);
}


return sh;
}
}

以下文章是一个很好的信息来源:

可靠性最佳实践

Finally 块将在以下行之间运行:

message = "You will not win!";
return;