如果finally块抛出异常会发生什么?

Jac*_*ada 257 c# exception-handling exception try-catch-finally

如果finally块抛出异常,究竟会发生什么?

具体来说,如果在finally块的中途抛出异常会发生什么.是否调用了此块中的其余语句(之后)?

我知道异常会向上传播.

Hen*_*man 414

如果finally块抛出异常,究竟会发生什么?

该异常传播出来,并且(可以)在更高级别处理.

您的finally块将不会在抛出异常之外完成.

如果在处理早期异常期间执行finally块,则第一个异常将丢失.

C#4语言规范§8.9.5:如果finally块抛出另一个异常,则终止当前异常的处理.

  • +1:**完全**回答问题的唯一答案 (40认同)
  • 除非它是一个`ThreadAbortException`,否则整个finally块将首先完成,因为它是一个关键部分. (8认同)

Dir*_*mar 98

对于这些问题,我通常在Visual Studio中打开一个空的控制台应用程序项目并编写一个小示例程序:

using System;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            try
            {
                throw new Exception("exception thrown from try block");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Inner catch block handling {0}.", ex.Message);
                throw;
            }
            finally
            {
                Console.WriteLine("Inner finally block");
                throw new Exception("exception thrown from finally block");
                Console.WriteLine("This line is never reached");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Outer catch block handling {0}.", ex.Message);
        }
        finally
        {
            Console.WriteLine("Outer finally block");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

运行程序时,您将看到执行catchfinally执行块的确切顺序.请注意,抛出异常后finally块中的代码将不会被执行(事实上,在此示例程序中,Visual Studio甚至会警告您已检测到无法访问的代码):

Inner catch block handling exception thrown from try block.
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block

补充说明

正如Michael Damatov指出的那样,try如果你不在(内部)catch块中处理它,那么块中的异常将被"吃掉" .实际上,在上面的示例中,重新抛出的异常不会出现在外部catch块中.为了更清楚地看一下下面稍微修改过的样本:

using System;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            try
            {
                throw new Exception("exception thrown from try block");
            }
            finally
            {
                Console.WriteLine("Inner finally block");
                throw new Exception("exception thrown from finally block");
                Console.WriteLine("This line is never reached");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Outer catch block handling {0}.", ex.Message);
        }
        finally
        {
            Console.WriteLine("Outer finally block");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

从输出中可以看出,内部异常是"丢失"(即忽略):

Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block

  • +1:比仅仅引用规范更有用的答案. (8认同)
  • @Theofanis Pantelides:不,一个`finally`块将(几乎)总是被执行,这也适用于内部finally块(只需自己尝试一下示例程序)(在这种情况下,一个finally块不会被执行)不可恢复的异常,例如`EngineExecutionException`,但在这种情况下,您的程序无论如何都会立即终止). (3认同)
  • 因为你在内部捕获中引发了异常,所以在这个例子中永远不会达到'Inner finally block' (2认同)

Guf*_*ffa 10

如果存在异常挂起(当try块具有finally但不存在时catch),则新异常将替换该异常.

如果没有异常挂起,它就像在finally块外抛出异常一样.


Dar*_*rov 6

异常被传播。

  • @bitbonk:像往常一样,从内到外。 (2认同)

lxa*_*lxa 5

保存“原始异常”(在try块中抛出)并牺牲“最终异常”(在finally块中抛出)的快速(且相当明显)片段,以防原始异常对您更重要:

try
{
    throw new Exception("Original Exception");
}
finally
{
    try
    {
        throw new Exception("Finally Exception");
    }
    catch
    { }
}
Run Code Online (Sandbox Code Playgroud)

执行上述代码时,“原始异常”向上传播调用堆栈,而“最终异常”丢失。