7

另一个面试问题是期待一个真/假的答案,我不太确定。

复制

4

9 回答 9

29

finally大部分时间被执行。这几乎是所有情况。例如,如果在线程上抛出异步异常(如StackOverflowException, OutOfMemoryException, ),则无法保证执行。这就是为编写高度可靠的代码而存在约束执行区域的原因。ThreadAbortExceptionfinally

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

于 2009-05-07T10:57:01.230 回答
8

直接来自 MSDN:

finally 块对于清理在 try 块中分配的任何资源很有用。不管 try 块如何退出,控制总是传递给 finally 块。

catch 用于处理语句块中发生的异常,而 finally 用于保证语句块的执行,而不管前面的 try 块如何退出。

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

于 2009-05-07T10:46:30.633 回答
8

通常,该finally块保证执行。

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

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

例如,在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();
   }
}

catch在这两种情况下,进程都在和之前终止finally

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

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

于 2009-05-07T11:03:15.973 回答
4

是的,finally 总是被执行。

于 2009-05-07T10:44:59.997 回答
4

finally 总是会被执行的说法并不完全正确。请参阅Haacked这个答案

两种可能:

  • StackOverflowException
  • ExecutingEngineException

当存在 StackOverflowException 时,finally 块将不会被执行,因为堆栈上没有空间可以执行更多代码。出现ExecutingEngineException时也不会调用,这种情况非常少见。

但是,这两个异常是您无法恢复的异常,因此基本上您的进程无论如何都会退出。

正如 Mehrdad 所提到的,可靠的 try/catch/finally 必须使用受约束的执行区域 (CER)。MSDN 提供了一个示例:

[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;
    }
}
于 2009-05-07T10:56:09.657 回答
1

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

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

于 2009-05-07T10:45:08.873 回答
0

finally 每次都会发生在 try catch 块中

于 2009-05-07T10:45:50.883 回答
0

无论是否抛出异常,都会执行“Finally”。

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

于 2009-05-07T10:49:03.573 回答
-2

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

于 2009-05-07T11:11:11.167 回答