为什么在引发异常时最终无法执行块?

时间:2020-02-10 20:52:43

标签: c# exception try-catch finally try-finally

很长一段时间以来,我认为它可以释放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
        }
    }
}

我从未到达打印到控制台的行。这意味着在这种情况下,我将无法释放finally块中的资源,除非抛出了try块中的异常。

因此,我相信有两件事:我遗漏了一些东西,或者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

4 个答案:

答案 0 :(得分:8)

您的假设是错误的(有时)https://dotnetfiddle.net/hjqmOS

try-finally (C# Reference)

通过使用finally块,您可以清理所有 分配在try块中,即使出现异常也可以运行代码 发生在try块中。通常,finally块的语句 当控件离开try语句时运行。可以转移控制权 因正常执行,执行中断而发生 继续,转到或返回语句,或传播异常 在try语句之外。

在某些情况下它仍然无法运行

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

这是重要的部分

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

答案 1 :(得分: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
}

答案 2 :(得分: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"); 
    }
}
}

答案 3 :(得分:0)

我想分享通过CLR 摘录自 C#的以下摘录,这对我来说很清楚,为什么最终块可能不会被调用。

如果在try块(或在try块内调用的任何方法)中执行的代码引发异常,则CLR开始搜索其catch类型与或相同的catch类型的catch块。 引发的异常的基本类型。如果没有任何捕获类型与异常匹配,则CLR继续 在调用堆栈中搜索以查找与异常匹配的捕获类型。如果达到 在调用堆栈的顶部,找不到匹配类型的catch块,未处理的异常 发生。

一旦CLR找到具有匹配catch类型的catch块,它将在所有内部执行代码 最终块,从其代码引发异常的try块开始并停止 与匹配异常的catch块。请注意,与 与异常匹配的catch块尚未执行。最终代码中的代码不会 执行直到处理catch块中的代码执行完。

执行完内部finally块中的所有代码之后,处理catch块中的代码 执行。

因此,这意味着在发生任何未处理的异常的情况下,不会调用 finally (最终)块。