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

Posted

技术标签:

【中文标题】如何处理封装了一次性实例的类?【英文标题】:How to deal with a class than encapsulates a disposible instance? 【发布时间】:2011-06-01 17:27:59 【问题描述】:
interface IMyInterace

void Open();
object Read();
void Close();


class MyImplementation : IMyInterface

public void Open()  /* instantiates disposible class */ 
//...
public void Close()  /* calls .Dispose(); */ 


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

我正在考虑这样做:

在 MyImplementation 中实现 IDisposible。 将 Dispose() 设置为调用 Close()。 添加对 Close() 或 Dispose() 的调用到 开始开放,以确保以前 通话已结束。

IMyInterface 的用户不知道他们使用的是什么实现,所以我不确定使 MyImplementation disposible 有多少价值,而且并非所有实现都会封装 IDisposibles。

【问题讨论】:

【参考方案1】:

处理这个问题的标准方法是让MyImplementation 实现IDisposable

【讨论】:

【参考方案2】:

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

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

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

一定要遵循完全一次性的模式,这比简单地实现接口更复杂:

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;

【讨论】:

您不需要完整的 Disposable 模式。不需要析构函数,因此不需要 SuppressFinalize。【参考方案3】:

除了这里已经有的答案:

如果这个类(经常/有时)仅通过接口使用,我建议从 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


【讨论】:

以上是关于如何处理封装了一次性实例的类?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理基于时间的一次性密码的 26 字节秘密?

如何处理我的 AWS EC2 实例上的多个 Python 请求?

vue 第一次axios请求得到一个数组,然后根据循环数组获得id进行第二次axios请求,请问如何处理速度最快?

消息队列如何处理重复消息

海量日志数据如何处理统计?

后端一次性传了10w条数据,前端该如何处理?—— 面试高频