【问题标题】:When shouldn't I implement IDisposable?我什么时候不应该实现 IDisposable?
【发布时间】:2013-09-09 23:13:53
【问题描述】:

首先,如果这被认为是重复的,很抱歉 - 我知道这是一个常见的话题,但我已经查看并没有找到满意的答案。

有很多问题询问何时使用IDisposable,但从我读过的所有内容来看,我只是不明白为什么你不会在你制作的每个类中实现它.有什么可失去的?它对性能有很大影响吗?

我对@9​​87654324@ 的部分理解是它所做的其中一件事是: Dispose()ing other IDisposables owned by the object。请原谅我的无知,但这仅适用于给定对象的字段/属性,还是也扩展到在其方法中创建的对象?

例如,如果在实现IDisposable 的类中的方法内创建了Font,但Font 没有使用using 块初始化,或者.Dispose()d 在末尾显式初始化方法;当它的IDisposable parent/class 被 GCd/disposed 时,它会被处理掉吗?否则,Font 是否永远不会被处置?

我并不是要跑题,但如果它确实会像这样“包罗万象”(有效地处理任何错误的子 IDisposable 对象,否则这些对象将不会被处理),不是仅凭这个理由就足以证明总是尽可能实施IDisposable

【问题讨论】:

  • 嗯,是的。如果您需要释放资源.. 遵循已经建立的模式。实现IDisposable..
  • 查看这个问题,它提出了相反的问题。 IDisposable 应该仅在您真正需要时才实施(特别是因为如何正确实施它并不明显)stackoverflow.com/questions/1125693/…
  • 一般来说,我发现我很少需要保留长期存在的 IDisposable 实例,尤其是在使用 async/await 的情况下,因此为每个实例实现 IDisposable 将是非常过分的。并非所有类都是 UI 类。
  • 感谢大家的 cmets...@SimonWhitehead:虽然您的逻辑毫无疑问,但恐怕我发现它并不能真正回答我的问题。
  • @Alfie:如果您通过在方法中创建 Font 而不进行处置而丢失了对 IDisposable 对象的引用,那么您将无能为力。如果丢失的 IDisposable 被正确实现,那么 GC 对终结器的调用应该会清理干净。

标签: c# .net memory-management memory-leaks idisposable


【解决方案1】:

一个对象应该实现IDisposable,如果它知道在宇宙终结之前的某个时间需要发生的事情,并且没有其他任何东西具有确保这些事情完成所必需的知识和动力; Dispose 方法让对象知道它最好立即执行这些操作,否则它们可能永远无法完成。

一个抽象类型或接口应该实现IDisposable,如果派生或实现该类型的实例可能知道在宇宙终结之前某个时间需要发生的事情,持有引用的最后一个实体很容易知道它是从抽象或接口类型派生或实现的事物的实例,而不是实现实现IDisposable 的更具体类型的事物。

实现继承IDisposable 的接口的类型将被要求实现IDisposable,无论它是否有任何其他原因。

有理由实现IDisposable 的类型应该这样做。不应该的类型,不应该。

附录

要了解为什么不应该总是实施IDisposable,考虑这样做的实际成本可能会有所帮助。处理器调用无操作Dispose 方法所需的时间是微不足道的,但这不是真正的考虑因素。当人们认为大多数对象符合以下四种描述之一时,就会出现更大的问题:

  • 封装资源的对象,需要有一个明确的所有者

  • 封装可变状态的对象,需要有一个明确定义的所有者。

  • 不可变类型的对象,不需要明确定义的所有者。

  • 永远不会暴露给可能改变它们的代码的可变类型实例,并且不需要明确定义的所有者。

正确使用可变对象通常需要跟踪谁拥有它们,就像拥有资源的对象一样。同样,如果使用具有可变状态的对象来封装另一个对象的可变状态,则正确使用后一个对象将需要跟踪谁拥有它,就像对象封装拥有资源的其他对象一样。具有资源的对象和具有可变状态的对象之间的区别在于,当使用可变类型的实例来封装不可变对象的状态时(确保实例永远不会暴露给会对其进行变异的代码),它将不再有必要跟踪谁拥有它。相比之下,有必要跟踪封装了其他持有资源的对象的对象的所有权,即使这些对象在语义上是不可变的。

【讨论】:

    【解决方案2】:

    规则很简单,如果你的类中有任何字段属于一次性类型,则需要实现 IDisposable。以便您处理它们。

    方法内部发生的事情与您的类的字段几乎没有关系。如果您创建字体并将其存储在字段中,那么是的,上面的规则说您需要一个 Dispose() 方法。如果你不只是像平常一样使用字体来绘制东西,那么请始终使用 using 语句,以便在使用完字体后立即处理它。

    【讨论】:

    • 感谢@HansPassant,这很有帮助。所以我可以正确地得出结论,包含类的Dispose() 方法对在其他方法中创建的变量没有影响(在类实例的生命周期内)?在这种情况下,没有usingDispose()Font 只会成为MIA?
    • 您编写 Dispose() 方法,没有什么是自动魔术。不,您不能在 Dispose() 方法中访问另一个方法的局部变量。这些变量在很久以前就消失了。
    • 我认为是这样 - 感谢您的确认。但是不实现IDisposable 是否意味着它的子/一次性字段也会自动调用它们的Dispose(),而不必在类的 Dispose 方法中显式调用它们?
    • @Alfie:不,它没有。
    • +1。请注意,“拥有任何字段”有些错误,“拥有任何字段并拥有对象”可能会更好。在某些情况下,对象的字段包含IDisposable,但对象不拥有IDisposable。在这种情况下,您不得在您的对象内部处置IDisposable(并且可能不应该在该对象上实现IDisposable)。示例可以是将参数打包到方法的包装类(即{destinationName, stream} 作为某些CopyTo 方法的参数)。
    【解决方案3】:

    大多数对象不需要它。该框架很好地照顾了Garbage CollectionCOM 对象和Graphics 对象属于那些可以并且应该实现IDisposable 以进行良好清理的对象。是的,回收对象时可能会有一些固有的性能损失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 2020-06-03
      • 1970-01-01
      • 2010-12-30
      • 2013-10-31
      相关资源
      最近更新 更多