2012-11-26 221 views
3

我对正确实现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),但我似乎无法找到正确的方式来构造这个的具体例子。

回答

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(); 
    } 
} 
+0

谢谢汉斯,非常有用。冒着滥用你的帮助的风险,你对在类中创建的一次性对象的处理有什么看法,而不是那些作为参考提供的对象 - 例如在类构造器中? – Neilski

+0

这是你需要自己解决的问题。谁成为对象的“所有者”?在完成使用之前,您无法真正承担创建Foo对象的其他代码。当您使用它时,其他代码也不会知道*。所以通常的做法是转让所有权,然后处置它。例如,也由.NET框架,StreamWriter(Stream)构造函数完成。 –

2

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

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

是的,应该的。否则,Dispose将被调用。但是,这将增加至少一代的物体寿命。这是由于类定义中的终结器。请参阅上面的文章链接。

2)如果一个可任意处理的对象作为引用传递给一个类,那么如果该类仍然对该引用对象调用Dispose()方法,或者它应该将它留给创建该对象的类第一名?

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

+0

谢谢你,所以,在上面的例子中,Bar应该创建一个标志,指示Foo是内部创建的还是作为参考传递的?然后可以在虚拟Dispose()方法中使用该标志来调用MyFoo.Dispose()或不调用。 – Neilski

+0

其实Foo。Dispose应该由Foo本身在内部实现。我的意思是国旗。在Bar.Dispose中,应该调用Foo.Dispose。重复处置的电话应该没有问题。此外,因为Bar创建MyFoo,所以MyFoo.Dispose只能在Bar中调用,而不能在其他任何类中调用。 – Tilak

+0

在某些情况下,接收实现“IDisposable”类型参数的对象将接受调用其上的Dispose的责任。 “IDisposable”的基本概念是“最后一个离开房间请关灯”。在任何时候,应该有可能确切地确定一个负责清理每个“IDisposable”的对象;该责任始于其创建者,但如果创作者为了某些其他对象的利益而创建对象并且不再需要它自己,则可能会被移交。 – supercat