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

发布于 2024-07-18 17:07:56 字数 702 浏览 6 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

洋洋洒洒 2024-07-25 17:07:56

finally大部分时间都会被执行。 几乎所有情况都是如此。 例如,如果线程上抛出异步异常(如 StackOverflowException、OutOfMemoryException、ThreadAbortException),那么finally不保证执行。 这就是为什么需要约束执行区域来编写高度可靠的代码。

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

finally is executed most of the time. It's almost all cases. For instance, if an async exception (like StackOverflowException, OutOfMemoryException, ThreadAbortException) is thrown on the thread, finally execution is not guaranteed. This is why constrained execution regions exist for writing highly reliable code.

For interview purposes, I expect the answer to this question to be false (I won't guarantee anything! The interviewer might not know this herself!).

感情洁癖 2024-07-25 17:07:56

一般来说,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();
   }
}

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

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

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

Generally the finally block is guaranteed to execute.

However, a few cases forces the CLR to shutdown in case of an error. In those cases, the finally block is not run.

One such example is in the presence of a StackOverflow exception.

E.g. in the code below the finally block is not executed.

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

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

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

In both cases the process terminates before both catch and finally.

I'll admit that the examples are very contrived, but they are just made to illustrate the point.

Fortunately neither happens very often.

凉城 2024-07-25 17:07:56

直接来自 MSDN:

finally 块对于
清理分配的所有资源
try 块。 控制始终是
无论如何传递到finally块
try 块如何退出。

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

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

Straight from MSDN:

The finally block is useful for
cleaning up any resources allocated in
the try block. 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(VS.71,loband).aspx

懒猫 2024-07-25 17:07:56

是的,finally 总是被执行。

Yes, finally is always executed.

等你爱我 2024-07-25 17:07:56

finally 总是会被执行,这并不完全正确。 请参阅这个答案< /a> 来自 黑客攻击

两种可能性:

  • StackOverflowException
  • ExecutingEngineException

finally块不会被执行
当出现 StackOverflowException 时
因为堆栈上没有空间
甚至执行更多代码。 它会
当有一个时也不会被调用
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;
    }
}

It is not totally true that finally will always be executed. See this answer from Haacked:

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.

However, these two exceptions are exception you cannot recover from, so basically your process will exit anyway.

As mentioned by Mehrdad, a reliable try/catch/finally will have to use Constrained Execution Regions (CER). An example is provided by 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;
    }
}
春夜浅 2024-07-25 17:07:56

一般来说,无论是否抛出异常以及是否处理异常,finally 块都会被执行。

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

Generally the finally block is always executed regardless of whether an exception is thrown or not and whether any exception is handled or not.

There are a couple of exceptions (see other answers for more details).

逆蝶 2024-07-25 17:07:56

对于该 try catch 块,最终每次都会发生

Finally will happen everytime for that try catch block

演多会厌 2024-07-25 17:07:56

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

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

'Finally' is executed regardless of whether an exception is thrown or not.

Its a good place to close any open connections. Successful or failed execution, you can still manage your connections or open files.

失而复得 2024-07-25 17:07:56

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

Finally is always executed. I not depends on how the try block works.
If u have to do some extra work for both try and cath, it is better to put in finally block. So you can gurantee that it is always executed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文