在C#中,如果抛出未处理的异常,finally块会在try,catch中执行吗?

时间:2009-05-07 10:43:34

标签: c# .net finally

10 个答案:

答案 0 :(得分:27)

finally大部分时间执行。这几乎是所有情况。例如,如果在线程上抛出异步异常(如StackOverflowExceptionOutOfMemoryExceptionThreadAbortException),则无法保证执行finally。这就是为编写高可靠性代码而存在constrained execution regions的原因。

对于面试目的,我希望这个问题的答案是 false (我不保证任何事情!面试官可能不会自己知道!)。

答案 1 :(得分:8)

通常,finally块保证执行。

但是,少数情况会强制CLR在发生错误时关闭。在这些情况下,finally块不会运行。

一个这样的例子是存在StackOverflow异常。

E.g。在下面的代码中,finally块未执行。

static void Main(string[] args) {
   try {
      Foo(1);
   } catch {
      Console.WriteLine("catch");
   } finally {
      Console.WriteLine("finally");
   }
}

public static int Foo(int i) {
   return Foo(i + 1);
}

我知道的另一种情况是终结器是否会引发异常。在这种情况下,该过程也会立即终止,因此保证不适用。

下面的代码说明了问题

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();
   }
}

在这两种情况下,流程都会在catchfinally之前终止。

我承认这些例子非常人为,但它们只是为了说明这一点。

幸运的是,这种情况经常发生。

答案 2 :(得分:7)

直接来自MSDN:

  

finally块非常有用   清理分配的任何资源   试块。总是控制   无论如何传递给finally块   如何退出try块。

     

而catch用于处理   声明中出现的异常   块,最后是用来保证一个   语句代码块执行   不管前面的尝试如何   阻止退出。

http://msdn.microsoft.com/en-us/library/zwc8s4fz(VS.71,loband).aspx

答案 3 :(得分:4)

是的,最后总是被执行。

答案 4 :(得分:3)

最终将永远执行并不完全正确。请参阅this answer中的Haacked

  

两种可能性:

     
      
  • StackOverflowException
  •   
  • ExecutingEngineException
  •   
     

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

但是,这两个例外情况是您无法恢复的例外情况,所以基本上您的流程无论如何都会退出。

如Mehrdad所述,可靠的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;
    }
}

答案 5 :(得分:1)

通常无论是否抛出异常以及是否处理任何异常,都始终执行finally块。

有几个例外(有关详细信息,请参阅其他答案)。

答案 6 :(得分:0)

无论是否抛出异常,

'finally'都会被执行。

这是关闭任何开放连接的好地方。执行成功或失败,您仍然可以管理您的连接或打开文件。

答案 7 :(得分:-1)

最后,每次尝试捕获块

都会发生

答案 8 :(得分:-1)

最后保证在任何情况下都会执行阻止。

答案 9 :(得分:-1)

最后总是执行。我不依赖于try块的工作原理。 如果你必须为try和cath做一些额外的工作,最好放入finally块。所以你可以保证它总是被执行。