关于try catch:C#“finally”阻止总是执行吗?

Does the C# “finally” block ALWAYS execute?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Will code in a Finally statement fire if I return a value in a Try block?

考虑以下代码C代码。"finally"块是否执行?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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中测试这篇文章。不过,请随时回答!


不,不是。如果应用程序仍在运行,它将始终执行(除非在fastfail异常、msdn链接期间,如其他人指出的那样)。它将在退出块的Try/Catch部分时执行。

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


根据try声明的msdn c规范:

The statements of a finally block are always executed when control leaves a try statement. This is true whether the control transfer occurs as a result of normal execution, as a result of executing a break, continue, goto, or return statement, or as a result of propagating an exception out of the try statement.

来源

在某些情况下,finally块将不执行:

  • 环境.failfast
  • 不可捕获的异常类型
  • 电源故障

  • 执行finally并非完全正确。请看哈克的回答:

    Two possibilities:

    • StackOverflowException
    • ExecutingEngineException

    The finally block will not be executed
    when there's a StackOverflowException
    since there's no room on the stack to
    even execute any more code. It will
    also not be called when there's an
    ExecutingEngineException, which is
    very rare.

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

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

    事实上,还有至少一种情况是,在现已删除的问题中,没有按照Brian Rasmussen的描述执行finally

    The other case I am aware of is if a
    finalizer throws an exception. In that
    case the process is terminated
    immediately as well, and thus the
    guarantee doesn't apply.

    The code below illustrates the problem

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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)。MSDN提供了一个示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    [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


    是的,它有:-)http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx


    来自msdn try finally(C参考)

    The finally block is useful for
    cleaning up any resources allocated in
    the try block as well as running any
    code that must execute even if there
    is an exception. Control is always
    passed to the finally block regardless
    of how the try block exits.


    最后一个块将在这些行之间运行:

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


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

    The finally block is useful for
    cleaning up any resources allocated in
    the try block as well as running any
    code that must execute even if there
    is an exception. Control is always
    passed to the finally block regardless
    of how the try block exits.

    Whereas catch is used to handle
    exceptions that occur in a statement
    block, finally is used to guarantee a
    statement block of code executes
    regardless of how the preceding try
    block is exited.

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


    不,它没有。

    但只有一条路可以绕过它,那就是Environment.FailFast()。请参阅http://msdn.microsoft.com/de-de/library/ms131100.aspx。在其他任何情况下,都保证执行终结器;-)

    The FailFast method writes the message
    string to the Windows Application
    event log, creates a dump of your
    application, and then terminates the
    current process. The message string is
    also included in error reporting to
    Microsoft.

    Use the FailFast method instead of the
    Exit method to terminate your
    application if the state of your
    application is damaged beyond repair,
    and executing your application's
    try/finally blocks and finalizers will
    corrupt program resources.


    正确的答案是肯定的。

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


    是的,finally总是执行,现在不管finally块中的代码是否会导致异常都是另一回事。


    简单回答是。但这条规则也有一些"例外"。