为什么抛出异常时 finally block 可能无法执行?

Why finally block may not execute when exception is thrown?

提问人:qqqqqqq 提问时间:2/11/2020 最后编辑:Alexei Levenkovqqqqqqq 更新时间:2/15/2020 访问量:4187

问:

很长一段时间以来,我认为它允许我释放区块中的所有资源,并且我认为如果区块中发生异常,那么区块中的资源仍将释放。但事实似乎并非如此。finallytryfinally

我有以下一段代码:

using System;

public sealed class Program
{

    public static void Main()
    {
        try {
            int zero = 0;
            int i = 1/zero;
        } finally {
            Console.WriteLine("divide by zero"); //the line is never called
        }
    }
}

我从未到达打印到控制台的行。这意味着在这种情况下,我将无法释放块中的资源,因为异常被抛入块内。finallytry

所以,我相信有两件事:要么我遗漏了一些东西,要么 + 组合在 C# 中没有用例。第二句话是有道理的,因为我将获得与上述代码相同的功能,并使用下面的代码:tryfinally

using System;

public sealed class Program
{

    public static void Main()
    {
            int zero = 0;
            int i = 1/zero;

            Console.WriteLine("divide by zero"); //the line is never called
    }
}

但我担心我可能会在这里遗漏一些东西。那么,有人可以确认该组合是无用的或证明它不是无用的吗?

更新

在能够在其小提琴中调用块的注释之后,我再次检查了 VS Code,但仍然没有看到任何输出。finally

enter image description here

C# 异常 try-catch try-finally

评论

1赞 Johnathan Barclay 2/11/2020
@MichaelRandall 尝试使用 .NET Core 编译器:dotnetfiddle.net/8hLq8h
0赞 qqqqqqq 2/11/2020
@JohnathanBarclay,哦。你是我的救星。这是由于 .NET Core 转换,而我习惯了 .NET Framework。非常感谢。
0赞 qqqqqqq 2/11/2020
@JohnathanBarclay,我相信你的评论是我一直在寻找的答案。你能把它添加为答案吗?
0赞 T.S. 2/11/2020
这回答了你的问题吗?C# 尝试捕捉混淆
1赞 Johnathan Barclay 2/11/2020
@qqqqqqq 迈克尔·兰德尔(Michael Randall)的回答解释了实际原因。我的小提琴只是一个观察。

答:

11赞 TheGeneral 2/11/2020 #1

你的假设是不正确的(有时)https://dotnetfiddle.net/hjqmOS

try-finally(C# 参考)

通过使用 finally 块,您可以清理任何 在 try 块中分配,即使出现异常也可以运行代码 在 try 块中发生。通常,finally 块的语句 当控件离开 try 语句时运行。控制权的转移可以 由于正常执行,执行中断而发生, continue、goto 或 return 语句,或传播异常 out of the try 语句。

但在某些情况下,它不会运行

在处理的异常中,关联的 finally 块是有保证的 要运行。但是,如果异常未处理,则执行 最后,块取决于异常展开操作的方式 触发。反过来,这取决于您的计算机的设置方式。

这是重要的部分

通常,当未经处理的异常结束应用程序时,无论 不是最后块运行并不重要。但是,如果您有 finally 块中的语句,即使在这种情况下也必须运行, 一种解决方案是在 try-finally 语句中添加一个 catch 块。 或者,您可以捕获可能在 try-finally 语句的 try 块位于调用堆栈的上方。

评论

1赞 Broots Waymb 2/11/2020
哇。。不知道最后一句话中的警告。似乎有点违反直觉......但话又说回来,我认为我实际上不需要阅读 try/catch 的文档(或者我是这么认为的!
3赞 TheGeneral 2/11/2020
@BrootsWaymb令人惊讶的是,那些讨厌的文档中隐藏着什么:)
0赞 qqqqqqq 2/11/2020
@MichaelRandall,这是否意味着 .NET Core 支持最后一个文档引用,但 .NET Framework 不支持?
0赞 TheGeneral 2/11/2020
简而言之,@qqqqqqq使用 a 来处理异常,以尝试确保某些内容正在运行。不依赖环境catch-finally
0赞 qqqqqqq 2/11/2020
@MichaelRandall,明白了。谢谢。你能告诉我这意味着什么吗?我在文档中找不到任何解释这一点的内容。exception unwind operation triggering
1赞 T.S. 2/11/2020 #2

try/catch/finally与释放资源无关。这是严格的应用程序流和错误处理构造。您生活在托管代码中,垃圾回收器释放了资源。此构造执行以下操作

try
{
    int zero = 0;
    int i = 1/zero;
}
catch (DividedByZeroException ex)
{
    Console.WriteLine(Exception handled);
    throw; // propagate ex to caller
}
finally
{
    Console.WriteLine("Method ended execution"); // called with or without exception
}

评论

0赞 Jonathon Chase 2/11/2020
@qqqqqqq 如果 T.S. 投了重复票,而另外两票投了偏离主题的票,则 T.S. 的投票将计入偏离主题的结束票。
0赞 qqqqqqq 2/11/2020
@JonathonChase,哦。还有一个有用的信息。谢谢。
0赞 qqqqqqq 2/11/2020
@T.S.,我很抱歉。看来我的指控是由于我缺乏知识而发生的。
0赞 T.S. 2/11/2020
@qqqqqqq 此外,系统会自动在我的行为上添加评论。"Does this answer your question?"
1赞 Tim 2/11/2020 #3

我相信这是因为您有 VS 来破坏未处理的错误,因此 VS 步骤显示异常。如果你编译它并在命令行上手动运行它,我相信你会看到“除以零”。此外,您可以“处理”错误,然后看到预期的行为,而不是更改 VS 设置。

例:

using System;

public sealed class Program
{

public static void Main()
{
    try
    {
        int zero = 0;
        int i = 1 / zero;
    }
    catch
    {

    }
    finally
    {
        Console.WriteLine("divide by zero"); 
    }
}
}

评论

0赞 qqqqqqq 2/11/2020
是的。我看到正在添加块的输出。谢谢。catch