IDisposable.Dispose 在 using 块出现异常后永远不会被调用

IDisposable.Dispose is never called after exception in using block

我从 this and this 等许多来源了解到,如果在 Using 块中抛出异常,将始终调用 IDisposableDispose 方法。那么我有这个代码:

static class MainEntryPoint
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;

        using (var x = new Disposable())
        {
            throw new Exception("asdfsdf");
        }
    }

    private static void HandleUnhandledException(Object sender, System.UnhandledExceptionEventArgs e)
    {
        Environment.Exit(0);
    }
}

class Disposable : IDisposable
{
    public void Dispose()
    {
        System.Diagnostics.Debug.Print("I am disposed");
    }
}

它在抛出未处理的异常时退出应用程序。 Dispose 方法永远不会被调用。为什么?

Environment.Exit 将终止程序

If Exit is called from a try or catch block, the code in any finally block does not execute. If the return statement is used, the code in the finally block does execute.

using (var x = new Disposable())
{
    throw new Exception("asdfsdf");
}

将转换为

Disposable x = new Disposable();
try
{
    throw new Exception("asdfsdf");
}
finally
{
    if (x != null)
        x.Dispose();
}

没错!由于在事件处理程序中调用了 Environment.Exit(0),因此无法调用 Dispose 方法中的代码。

尝试删除对 Environment.Exit(0) 的调用并查看是否调用了 Debug.Print()。

请注意,如果您已将终结器添加到 Disposable,例如:

public class Disposable : IDisposable
{
    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        Console.WriteLine("I am disposed");

        if (disposing)
        {
            GC.SuppressFinalize(this);
        }
    }

    ~Disposable()
    {
        Dispose(false);
    }
}

(因此使用 "full" IDisposable 模式),然后 "normally" 终结器将被调用(因为终结器有机会 运行 在 Environment.Exit),该方法将调用 Dispose(bool disposing)。请注意,即使在这里,终结器也有可能不是 运行,因为它们有时间限制 运行、see.