为什么当抛出异常时,finally块可能不会执行?

3
很长一段时间,我认为finally块可以让我释放所有资源,如果try块中发生异常,那么资源仍然会在finally块中释放。但事实似乎并非如此。
以下是我的代码片段:
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
        }
    }
}

我从未达到在控制台输出的那一行。这意味着当异常在try块内被抛出时,我将无法在finally块中释放资源。
因此,我认为有两种情况:要么我漏了什么,要么try+finally组合在C#中没有用例。第二种说法是有道理的,因为我可以通过以下代码获得与上面代码产生的相同功能:
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
    }
}

但我担心我可能在这里漏掉了什么。所以,有人能否确认组合是无用的或证明它不是无用的,请?

更新

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

enter image description here

1
@MichaelRandall 请尝试使用.NET Core编译器:https://dotnetfiddle.net/8hLq8h - undefined
@JohnathanBarclay,哦。你真是我的救星。这是由于.NET Core的转换,而我习惯了.NET Framework。非常感谢你。 - undefined
@JohnathanBarclay,我相信你的评论就是我在寻找的答案。你能否把它作为一个回答添加进来呢? - undefined
1
@qqqqqqq Michael Randall的回答解释了实际原因。我的示例只是一种观察。 - undefined
没有思考过程;我现在通常在.NET Core中测试所有东西,我观察到和你一样的行为。 - undefined
显示剩余5条评论
3个回答

11
你的假设是不正确的(有时候)https://dotnetfiddle.net/hjqmOS try-finally (C#参考)try-finally (C# Reference) 通过使用finally块,您可以清理在try块中分配的任何资源,并且即使try块中发生异常,也可以运行代码。通常,当控件离开try语句时,finally块的语句会执行。控制的转移可能是由于正常执行,break、continue、goto或return语句的执行,或由于将异常传播到try语句之外而发生的。
但有时不会运行
在已处理的异常内部,保证会运行相关的finally块。然而,如果异常未经处理,则finally块的执行取决于如何触发异常解旋操作。这反过来又取决于计算机的设置。
以下是重要部分
通常情况下,当未处理的异常结束应用程序时,是否运行finally块并不重要。但是,如果finally块中有必须在该情况下运行的语句,则一种解决方案是向try-finally语句添加catch块。或者,您可以在调用堆栈更高处捕获可能在try块中抛出的异常。

1
哇..对于最后一句话中的警告我完全不知道。看起来有点违反直觉...但是再想想,我想我从来没有真正需要阅读try/catch的文档(或者我以为如此!)。 - undefined
3
@BrootsWaymb:令人惊讶的是那些烦人文件中隐藏着什么:) - undefined
@qqqqqqq 简而言之,使用 catch-finally 来处理异常,以确保某些操作被执行。不要依赖于环境。 - undefined
@MichaelRandall,还有一件让我感到困惑的事情是,在C#中我们有using关键字。using模拟了try + finally的功能。那么,我们是否应该期望使用using会遇到相同类型的问题呢?(我并不指望你知道答案,可能其他人能够回答)。再次感谢你。 - undefined
@qqqqqqq hrm "猜测" 这取决于操作系统以及它如何解开堆栈。也许有更多了解内部机制的人可以回答这个问题。这很可能是另一个问题,而且是一个有趣的问题,可能会吸引那些更了解的人。 - undefined
显示剩余3条评论

1

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
}

如果T.S.投票选择重复问题,而其他两人投票选择不相关问题,那么T.S.的投票将计入不相关问题的关闭投票中。 - undefined
@JonathonChase,哦。还有一条有用的信息。谢谢你。 - undefined
@T.S.,我道歉。看起来我的指责是因为我对知识的不足而发生的。 - undefined
@qqqqqqq 此外,系统会自动代表我添加“这个回答解决了你的问题吗?”的评论。 - undefined

1
我认为这是因为你设置了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"); 
    }
}
}

是的,我看到了添加了catch块的输出。谢谢你。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接