可能重复:
Will code in a Finally statement fire if I return a value in a Try block?
考虑以下代码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中自己测试过。但是,请随时回答!
答案 0 :(得分:79)
不,不。如果应用程序仍在运行,它将始终执行(FastFail例外情况除外,MSDN link,与其他人一样)。它将在退出块的try / catch部分时执行。
如果应用程序崩溃,它将不会执行:通过kill process命令等被杀死。这非常重要,因为如果你编写绝对期望它运行的代码,比如手动进行回滚,如果不是其他明智的话它会自动提交,你可以遇到应用程序在发生之前中止的场景。老实说,这是一个外部场景,但在这些情况下注意很重要。
答案 1 :(得分:49)
来自try
语句的MSDN C#规范:
当控件离开
finally
语句时,始终会执行try
块的语句。无论控制转移是由于执行break
,continue
,goto
还是return
语句,还是作为正常执行而发生的,都是如此从try
语句中传播异常的结果。
有些情况下finally块不会执行:
答案 2 :(得分:33)
始终执行finally
并不完全正确。请参阅this answer中的Haacked:
两种可能性:
StackOverflowException
ExecutingEngineException
不会执行finally块 当有StackOverflowException时 因为堆栈上没有空间 甚至执行更多的代码。它会 当有一个时也不会被叫 ExecutingEngineException,这是 非常罕见。
事实上,对于任何类型的异步异常(如StackOverflowException
,OutOfMemoryException
,ThreadAbortException
),都无法保证执行finally
块。
但是,这些例外是您通常无法恢复的例外情况,在大多数情况下,您的流程仍会退出。
事实上,至少还有一个案例finally
未按现在Brian Rasmussen中的deleted question所述执行:
我知道的另一个案例是a 终结者抛出异常。在那里面 该过程终止的情况 马上也是如此 担保不适用。
下面的代码说明了问题
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必须使用Constrained Execution Regions (CER)。 MSDN提供example:
[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;
}
}
以下文章是一个很好的信息来源:
<强> Reliability Best Practices 强>
答案 3 :(得分:5)
答案 4 :(得分:4)
来自MSDN try-finally (C# Reference)
finally块非常有用 清理分配的任何资源 try块以及运行任何块 即使存在必须执行的代码 是一个例外。 始终控制 无论如何传递给finally块 如何退出尝试块。
答案 5 :(得分:2)
是的,在正常情况下(正如许多其他人所指出的那样)。
finally块非常有用 清理分配的任何资源 try块以及运行任何块 即使存在必须执行的代码 是一个例外。总是控制 无论如何传递给finally块 如何退出try块。
而catch用于处理 声明中出现的异常 块,最后是用来保证一个 语句代码块执行 不管前面的尝试如何 阻止退出。
答案 6 :(得分:2)
finally块将在这些行之间运行:
message = "You will not win!";
return;
答案 7 :(得分:1)
是的,finally
总是执行,现在finally块中的代码是否会导致异常是另一回事。
答案 8 :(得分:1)
正确答案是肯定的。
尝试调试你的程序并设置一个断点并观察控制是否仍然击中finally块。
答案 9 :(得分:1)
不,不。
虽然只有一种方法,但Environment.FailFast()
。见http://msdn.microsoft.com/de-de/library/ms131100.aspx。在所有其他情况下,保证终结器被执行; - )
FailFast方法写入消息 字符串到Windows应用程序 事件日志,创建您的转储 应用程序,然后终止 目前的过程。消息字符串是 也包含在错误报告中 微软。
使用FailFast方法代替 退出方法终止你的 申请如果您的状态 应用程序损坏无法修复, 并执行您的应用程序 try / finally块和终结器会 腐败的计划资源。
答案 10 :(得分:0)
简单回答是的。但该规则有一些“例外”。