为什么即使使用了using语句,Dispose方法也没有被调用?

4

我有一个控制台应用程序(.NET Framework 4.5.2):

class Program
{
    static void Main(string[] args)
    {
        using (var result = new Result())
        {
            result.Test();
        }
    }
}

public class Result : IDisposable
{
    public void Test()
    {
        int a = 1;
        int b = 1 / (a - 1);
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose");
    }
}

为什么Dispose方法没有被调用?在DivideByZero异常之后,断点没有被命中,并且控制台没有输出(因为应用程序已经退出)。


1
@jLaw 这个对象在 using 语句中,因此人们可能期望该对象在语句结束时被处理。 - Timothy Groote
3
是的,它调用了 dispose(在修复零除异常之后)。 - Renatas M.
3
你认为为什么这个电话没有被打过来? - Ofir Winegarten
1
@Reniuz 即使抛出异常,它也应该调用dispose。 - Ofir Winegarten
2
@TimothyGroote:程序出现了未捕获的异常。没有要求必须到达using子句的结尾;具有未捕获异常的程序具有实现定义的行为。 - Eric Lippert
显示剩余13条评论
1个回答

11
根据MS Docs的说法:try-finally (C# Reference) 在处理异常时,关联的finally块一定会被执行。但是,如果异常未经处理,那么finally块的执行取决于如何触发异常展开操作。这又取决于计算机的设置。
由于您没有捕获DivideByZero异常并让其未经处理,在您的计算机和设置上,它必须在运行任何其他代码之前关闭应用程序,因此不会运行finally块。
正如@Evk在下面的评论中指出的那样,如果我在没有附加调试器的情况下运行它,则会正确展开异常并执行finally块。每天都会学到新东西。
根据Eric Lippert的回答Finally Block Not Running?
考虑到该情况有多么糟糕:发生了意外情况,没有人编写代码来处理。在这种情况下应该做的正确事情是运行更多的代码吗?这些代码很可能也没有构建来处理这种情况。可能不是。在这种情况下,做正确的事情通常是不尝试运行finally块,因为这样做会使糟糕的情况变得更糟。您已经知道进程要关闭了,立即结束它的痛苦。
在未经处理的异常将关闭进程的情况下,任何事情都可能发生。在这种情况下,实现定义会发生什么:报告错误到Windows错误报告、启动调试器等等。CLR 完全有权尝试运行finally块,并且也完全有权快速失败。在这种情况下,所有赌注都关门;不同的实现可以选择做不同的事情。

不是每次都这样,某些例外会导致应用程序完全关闭(例如硬件异常)。我本来希望它能运行finally块,但我可以确认在我的机器上它永远不会进入Finally块。 - Michal Ciechan
1
你的措辞有误,因为你说这个 finally 永远 不会运行,而这并不是真的(你自己的引用说“这取决于情况”)。 - Evk
2
很可能OP在调试器下运行应用程序,这种情况下VS会在未处理的异常上终止进程(不会解开它)。如果OP在同一台机器和配置下不使用调试器运行,则会执行finally块。 - Evk
1
@Evk,我认为你应该把这个作为答案发布,因为我认为调试器应该在任何情况下都会运行finally块,而不是没有它。感谢你指出并且我可以确认在我的机器上你的说法是正确的。你知道这总是这种情况吗? - Michal Ciechan
2
据我所知,Visual Studio调试器在未处理的异常后总是会“终止”进程,不知道是否有任何方法可以避免这种情况。例如,您可以使用Environment.FailFast来模拟相同的情况。如果您执行try { ... some stuff ...; Environment.FailFast("some message");} finally {},则即使没有调试器,finally块也不会运行。或者您可以从任务管理器中终止进程。 - Evk
我认为你的回答在一般情况下是可以的,毕竟正如你引用 Eric Lippert 的话所说 - 这完全取决于实现。 - Evk

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