如何处理封装一次性实例的类?

时间:2010-12-30 19:37:02

标签: c# idisposable resource-management

interface IMyInterace
{
void Open();
object Read();
void Close();
}

class MyImplementation : IMyInterface
{
public void Open() { /* instantiates disposible class */ }
//...
public void Close() { /* calls .Dispose(); */ }

}

有没有一种很好的方法来处理这种情况,以确保调用类中的可处置实例? (除了在文档中,调用者没有信号称他们必须调用'Close'。)IMyInterface的实现不一定封装IDisposible实例,并且在整个应用程序的生命周期内重复关闭和重新打开。

我正在考虑这样做:

  • 在MyImplementation中实现IDisposible。
  • 设置Dispose()以调用Close()。
  • 添加对Close()或Dispose()的调用 公开的开始以确保以前 电话已经关闭。

IMyInterface的用户不知道他们正在使用什么实现,因此我不确定MyImplementation可处置的价值有多少,而且并非所有实现都会封装IDisposible。

3 个答案:

答案 0 :(得分:5)

处理此问题的标准方法是让MyImplementation实施IDisposable

答案 1 :(得分:3)

正如约翰所说,你的第一个要点是正确的。

有时,Close()方法在功能上与Dispose()同义,并且存在以保持与抽象的语义一致性。也就是说,补充Open()方法。其他时候,Close()会允许您重新打开,但Dispose()不应该。因此,你的第二个要点也很好。

子弹点3不一定适用,因为不应重复使用被处置物体。如果您需要再次呼叫Open(),则需要使用新实例。事实上,Open()方法应该在调用ObjectDisposedException后抛出Dispose()(通过检查私有disposed布尔标志)。如果您希望对象在关闭后支持重新打开,则可以考虑使用Debug.Assert()和/或在没有Open()的情况下调用Close()时抛出异常。这将有助于防止这些情况的草率管理。

请务必遵循完整的一次性模式,这比简单实现界面更为重要:

bool disposed;

public void Dispose() // don't make virtual!
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if(!disposed)
    {
        if(disposing) 
        {
            // dispose of managed resources here, for example:
            // if(resource != null) { resource.Dispose(); } 
        }
    }

    // dispose of unmanaged resources here 

    disposed = true;
}

答案 2 :(得分:1)

除了已经有的答案:

如果此类(通常/有时)仅通过接口使用,我建议从IDisposable继承IMyInterace。

这将让您的用户以一致的方式使用这些对象。缺点当然是您可能需要将(虚拟)Dispose方法添加到实际不需要它的类中。但好处在于一致性和灵活性:如果一个类在将来发生变化,那么它确实需要一个Dispose()?

最小的方法:

interface IMyInterace : IDisposable { }

sealed class MyImplementation : IMyInterface 
{   
   public void Open() { /* instantiates disposible class */ }

   public void Close() { /* calls _myField.Dispose(); */ }

   public void Dispose() { Close(); }  // only use this short form in a sealed class

}