带终结者的单身人士,但不是IDisposable

这是我从“CLR via C#”,“Effective C#”和其他资源中了解IDisposable和终结器的内容:

  • IDisposable用于确定性地清理托管和非托管资源。
  • 负责非托管资源(例如文件句柄)的类应实现IDisposable,并提供终结器以确保即使客户端代码未在实例上调用Dispose(),也会清除它们。
  • 只负责管理资源的类不应该实现一个终结器。
  • 如果你有一个终结器,那么你必须实现IDisposable(这允许客户端代码做正确的事情并调用Dispose(),而终结器可以防止漏掉的资源,如果他们忘记了)。
  • 虽然我理解上述理由并同意上述观点,但有一种情况是我认为有必要打破这些规则:负责非托管资源的单例类(例如提供对特定文件的单一访问点)。

    我相信在单例中有一个Dispose()方法总是错误的,因为单例实例应该在应用程序的整个生命周期中存在,并且如果有客户端代码调用Dispose(),那么你就被塞满了。 但是,您需要一个终结器,以便卸载该应用程序时,终结器可以清理非托管资源。

    因此,使用不带IDisposable的终结器的单例类似乎是合理的事情,但这种类型的设计与我所了解的最佳实践相反。

    这是一个合理的方法吗? 如果不是的话,为什么不,优越的选择是什么?


    如果非托管资源仅在应用程序退出时释放,则您甚至不需要担心终结器,因为无论如何,进程卸载都应该为您处理。

    如果您有多个应用程序域,并且您想要处理应用程序域卸载这是一个可能的问题,但可能是一个您不需要关心的问题。

    其次,我认为这种设计可能不是正确的做法(并且会使得难以解决的问题随后会发现您实际上需要两个实例)在入口点创建对象(或延迟加载包装器对象)并将其通过代码传递到需要的地方,明确谁负责将其提供给谁,然后你可以自由地改变决定,只使用一个对代码的其余部分影响很小的决定(它使用它得到的东西给出)


    我首先会提到面向对象的设计模式及其后果并不总是影响每一种语言决策,即使在面向对象的语言中也是如此。 您当然可以找到经典的设计模式,这些模式更容易用一种语言(Smalltalk)而不是另一种语言(C ++)来实现。

    这就是说,我不确定我是否同意单一实例只应用于应用程序末尾的前提。 我为Singleton(或设计模式:可重用面向对象软件的元素)阅读的设计模式描述中没有提到这是此模式的一个属性。 单身人士应确保在任何时刻只有一个班级实例存在; 这并不意味着只要应用程序存在就必须存在。

    我有一种感觉,实际上,在应用程序的大部分时间里,许多单身人士确实存在。 但是,考虑使用TCP连接与服务器通信的应用程序,但也可以以断开模式存在。 连接时,您希望单身人员保持连接信息和连接状态。 一旦断开连接,你可能想要保持同一个单身人士 - 或者你可以处理单身人士。 虽然有些人可能会争辩说保持单身人士更有意义(我甚至可能是其中的一员),但在设计模式本身中没有任何东西可以阻止您处理它 - 如果重新创建连接,则可以实例化单身人士再一次,因为在那个时候没有任何实例存在。

    换句话说,您可以创建情景,让单身人士拥有IDisposable。


    只要你的终结器不在任何其他管理对象上调用方法(比如Dispose),你应该没问题。 请记住,最终订单不是确定性的。 也就是说,如果你的单例对象Foo持有一个需要处理的对象Bar的引用,你不能可靠地写出:

    ~Foo()
    {
        Bar.Dispose();
    }
    

    垃圾收集器可能已经收集了Bar。

    冒着进入一堆OO goo的风险(即开始战争),使用单例的一种替代方法是使用静态类。

    链接地址: http://www.djcxy.com/p/9225.html

    上一篇: Singleton with finalizer but not IDisposable

    下一篇: Should I Dispose() DataSet and DataTable?