首页 文章

单身人士与终结者但不是IDisposable

提问于
浏览
14

这就是我对“CLR via C#”,“Effective C#”和其他资源的IDisposable和终结器的理解:

  • IDisposable用于确定性地清理托管和非托管资源 .

  • 负责非托管资源的类(例如文件句柄)应该实现IDisposable并提供终结器以保证它们被清除,即使客户端代码没有在实例上调用Dispose() .

  • 仅负责托管资源的类永远不应实现终结器 .

  • 如果你有一个终结器,那么你必须实现IDisposable(这允许客户端代码做正确的事情并调用Dispose(),而终结器可以防止泄漏资源,如果他们忘记) .

虽然我理解并推理上述所有内容,但有一种情况我认为打破这些规则是有意义的:负责非托管资源的单例类(例如提供对特定文件的单点访问) ) .

我认为在单例上使用Dispose()方法总是错误的,因为单例实例应该在应用程序的生命周期中存在,如果任何客户端代码调用Dispose(),那么你就被填充了 . 但是,您需要一个终结器,以便在卸载应用程序时,终结器可以清理非托管资源 .

因此,在我看来,使用没有实现IDisposable的终结器的单例类似乎是一件合理的事情,但这种类型的设计与我所理解的最佳实践相反 .

这是一种合理的方法吗?如果没有,为什么不呢?有哪些优越的选择?

6 回答

  • 3

    如果非托管资源仅在应用程序退出时释放,您甚至不需要担心终结器,因为进程卸载应该为您处理此问题 .

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

    我是第二个说这个设计可能不是正确的事情(并且会让你更难修复,随后你发现你确实需要两个实例)在你的入口点创建对象(或一个延迟的加载包装器对象)并通过代码传递给需要的地方,明确谁负责将其提供给谁,然后你可以自由地改变决定只使用一个对其余代码影响不大的代码(使用它得到的东西)给出)

  • 0

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

    话虽这么说,我'm not sure I agree with the premise that a singleton instance should only be disposed at the end of an application. Nothing in the design pattern descriptions that I'读了Singleton(或Design Patterns: Elements of reusable Object-Oriented Software)提到这个作为这种模式的属性 . 单身人士应该确保在任何一个时刻只存在一个 class 的实例;这并不意味着只要应用程序存在就必须存在 .

    我有一种感觉,在实践中,许多单身人士确实存在于应用程序的大部分生命中 . 但是,请考虑使用TCP连接与服务器通信的应用程序,但也可以以断开连接模式存在 . 连接时,您需要一个单例来维护连接信息和连接状态 . 断开连接后,您可能希望保留相同的单例 - 或者您可以处置单例 . 虽然有些人可能认为保持单例更有意义(我甚至可能在其中),但设计模式本身没有任何东西阻止你处理它 - 如果重新连接,单例可以被实例化再次,因为那个时刻没有它的实例存在 .

    换句话说,您可以创建场景,使单身人士具有IDisposable是合乎逻辑的 .

  • 0

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

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

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

    冒着踩到一堆OO粘性物质(即开始战争)的风险,使用单身人士的一种替代方案是使用静态等级 .

  • 6

    虽然它可能让你的代码审查gripes和FxCop警告,没有IDisposable实现终结器没有任何本质上的错误 . 但是,在单例上执行此操作并不是捕获进程或AppDomain拆除的可靠方法 .

    提供主观设计建议的风险:如果对象是真正的无状态,那么将其设为静态类 . 如果它是有状态的,那就问为什么它是Singleton:你正在创建一个可变的全局变量 . 如果您尝试捕获应用程序关闭,请在主循环退出时处理它 .

  • 2

    Singleton适用于任何特定情况,

    我认为处理单身人士没有任何问题 . 与惰性实例化相结合,它只是意味着如果您暂时不需要它,则释放资源,然后根据需要重新获取它 .

  • 4

    如果你想用终结器创建一个单例,你可能应该有一个WeakReference的静态引用 . 这将需要一些额外的工作来确保访问器中的线程安全性,但是当没有人使用它时,它将允许对单例进行垃圾收集(如果有人随后调用GetInstance()方法,它们将得到一个新实例) . 如果使用静态强引用,即使没有其他引用,它也会使单例实例保持活动状态 .

相关问题