C# 抛出异常时,为什么finally块不能执行?

C# 抛出异常时,为什么finally块不能执行?,c#,exception,try-catch,finally,try-finally,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; } fi

很长一段时间以来,我认为它允许我释放
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
块中抛出异常

因此,我相信有两件事:要么我遗漏了什么,要么
尝试
+
最后
组合在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代码,仍然没有看到任何输出


你的假设不正确(有时)

通过使用finally块,您可以清理所有被删除的资源 在try块中分配,即使出现异常,也可以运行代码 在try块中发生。通常,finally块的语句 当控件留下try语句时运行。控制权的转移可以 由于正常执行、中断执行而发生, continue、goto或return语句,或异常的传播 在try语句之外

但在某些情况下,它无法运行

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

这里是重要的部分

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


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
}

我相信这是因为您必须在未处理的错误上中断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"); 
    }
}
}

我想分享以下摘自C#via CLR一书的摘录,这本书向我阐明了为什么最终块可能不会被调用

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

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

内部finally块中的所有代码执行后,handling catch块中的代码 执行


因此,这意味着在任何未处理的异常情况下,finally块将不会被调用。

@MichaelRandall尝试使用.NET核心编译器:@JohnathanBarclay,oh。你是我的救星。这是由于.NET核心的转换,而我已经习惯了.NET框架。非常感谢。@JohnathanBarclay,我相信你的评论就是我想要的答案。请你把它作为一个答案加上好吗?这能回答你的问题吗@迈克尔·兰德尔的回答解释了实际原因。我的小提琴只是一种观察。是的。我看到添加了
catch
块的输出。谢谢。哇。。我不知道上一句话中的警告。似乎有点违反直觉。。。但是,再一次,我认为我从来没有真正需要阅读try/catch文档(或者我是这么认为的!)。@BrootsWaymb这些讨厌的文档中隐藏着令人惊讶的东西:)@MichaelRandall,这是否意味着最后的文档引用是由.NET核心支持的,而不是由.NET框架支持的?@qqq简而言之,使用
catch finally
来处理异常,以确保运行某个程序。不要依赖于环境environment@MichaelRandall,明白了。非常感谢。请您也告诉我触发
异常解卷操作的含义是什么?我在文档中找不到任何解释。@qqq如果T.S.投票赞成复制,而另外两个投票赞成离题,那就算作T了。