C#“最终”阻止总是执行吗?

时间:2010-07-09 19:49:23

标签: c# try-catch

  

可能重复:
  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中自己测试过。但是,请随时回答!

11 个答案:

答案 0 :(得分:79)

不,不。如果应用程序仍在运行,它将始终执行(FastFail例外情况除外,MSDN link,与其他人一样)。它将在退出块的try / catch部分时执行。

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

答案 1 :(得分:49)

来自try语句的MSDN C#规范:

  

当控件离开finally语句时,始终会执行try块的语句。无论控制转移是由于执行breakcontinuegoto还是return语句,还是作为正常执行而发生的,都是如此从try语句中传播异常的结果。

Source

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

  1. Environment.FailFast
  2. 无法捕获的异常类型
  3. 电源故障

答案 2 :(得分:33)

始终执行finally并不完全正确。请参阅this answer中的Haacked

  

两种可能性:

     
      
  • StackOverflowException
  •   
  • ExecutingEngineException
  •   
     

不会执行finally块   当有StackOverflowException时   因为堆栈上没有空间   甚至执行更多的代码。它会   当有一个时也不会被叫   ExecutingEngineException,这是   非常罕见。

事实上,对于任何类型的异步异常(如StackOverflowExceptionOutOfMemoryExceptionThreadAbortException),都无法保证执行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用于处理   声明中出现的异常   块,最后是用来保证一个   语句代码块执行   不管前面的尝试如何   阻止退出。

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

答案 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)

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