在 using 块中发生异常后,IDisposable.Dispose 从未被调用。

3
我从多个来源了解到,例如这里这里,如果在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 方法永远不会被调用。为什么?

3个回答

12

Environment.Exit 方法将终止程序。

如果 Exit 是在 try 或 catch 块中调用的,则任何 finally 块中的代码都不会执行。如果使用 return 语句,则 finally 块中的代码将会执行。

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

会被转换为

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

是的,使用语句确保即使出现异常也会调用Dispose。 - Gul Ershad

2
请注意,如果您已经为Disposable添加了终结器(finalizer),例如:
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);
    }
}

如果使用“完整”的IDisposable模式,那么通常情况下会调用终结器(因为在Environment.Exit上运行终结器的机会),并且该方法将调用Dispose(bool disposing)。请注意,即使在这里,终结器也有可能不会运行,因为它们有一个运行时间限制,请参阅


0

没错!由于在事件处理程序中调用了 Environment.Exit(0),所以不可能调用 Dispose 方法中的代码。

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


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