与IDisposable混淆

时间:2012-11-26 11:35:29

标签: c#-4.0 idisposable

我对实现IDisposable的正确方法有些疑惑。请考虑以下情况...

public class Foo : IDisposable {...}

public class Bar : IDisposable {

    private bool disposed = false;
    private readonly Foo MyFoo;

    public Bar() {
        this.MyFoo = new Foo();
    }
    public Bar(Foo foo) {
        this.MyFoo = foo;
    }
    ~Bar() {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
               if (MyFoo != null) {
                   this.MyFoo.Dispose();
                   this.MyFoo = null;
               }
            }
            this.disposed = true;
        }
    }

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

我的问题是:

1)如果一个类创建了一个一次性对象,它应该在自己的Dispose()方法中调用该对象上的Dispose()方法吗?

2)如果一个一次性对象作为引用传递给一个类,那么该类是否仍然在该引用对象上调用Dispose()方法,还是应该将它留给创建该对象的类?

上述模式似乎出现了很多(尤其是DI),但我似乎无法找到正确的结构方法的具体例子。

2 个答案:

答案 0 :(得分:2)

请参阅优秀的MSDN文章 Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework

  

1)如果一个类创建了一个一次性对象,它应该在自己的Dispose()方法中调用该对象上的Dispose()方法吗?

是的,应该。否则,也会调用Dispose。但这会增加至少1代对象的生命。这是由于类定义中的终结器。请参阅上面的文章链接。

  

2)如果一个一次性对象作为引用传递给一个类,那么该类是否仍然在该引用对象上调用Dispose()方法,还是应该将它留给创建该对象的类?

调用者(更具体地说是创建实例的类)负责调用Dispose方法。

答案 1 :(得分:1)

~Bar() {
    Dispose(false);
}

每当你发现自己编写这样的代码时,先深呼吸并问“我真的需要终结者吗?”您需要一个极为罕见,只有在您自己拥有非托管资源时才需要终结器。

第一个试金石是“终结者真的什么?”如果您遵循代码,那就很清楚了。它调用Dispose(false),并且该代码仅在参数为true时执行某些操作。接下来是不需要终结器。这是完全正常的,终结者是微软所担心的。他们编写了包装非托管资源的.NET框架类。 FileStream,Socket等。最重要的是,SafeHandle类,旨在包装操作系统句柄。他们有自己的终结者,你不要自己重写。

因此,如果没有终结器,代码将完全折叠为简单而正确的实现,您只需要调用自己存储的任何一次性对象的Dispose()方法:

public class Bar : IDisposable {
    private readonly Foo MyFoo;
    public Bar() {
        this.MyFoo = new Foo();
    }
    public void Dispose() {
        MyFoo.Dispose();
    }
}