45

如果我在 C# 中编写一个实现 IDisposable 的类,为什么不足以让我简单地实现

public void Dispose(){ ... } 

处理释放任何非托管资源?

protected virtual void Dispose(bool disposing){ ... }

总是必要的,有时是必要的,还是完全不同的东西?

4

8 回答 8

47

包括终结器、新虚拟方法的引入和原始 dispose 方法的“密封”在内的完整模式非常通用,涵盖了所有基础。

除非您对非托管资源有直接句柄(应该几乎 从不),否则您不需要终结器。

如果你密封你的类(我对尽可能密封类的看法现在可能众所周知 -设计继承或禁止它),那么引入虚拟方法是没有意义的。

我不记得我最后一次IDisposable以“复杂”的方式实现而不是以最明显的方式实现它,例如

public void Dispose()
{
    somethingElse.Dispose();
}

需要注意的一件事是,如果您要编写真正健壮的代码,则应确保在处理完之后不要尝试做任何事情,并ObjectDisposedException在适当的地方抛出。这对于世界各地的开发人员都将使用的类库是一个很好的建议,但如果这只是在您自己的工作空间中使用的类,那么这将是大量工作而收效甚微。

于 2009-02-25T06:33:10.647 回答
33

这不是绝对必要的。它是推荐的 Disposable 模式的一部分。如果你还没有阅读框架设计指南部分(第一版中的 9.3,没有方便的第二版,抱歉),那么你应该阅读。试试这个链接

它对于区分一次性清理和可终结的垃圾收集是非常有用的。

您不必那样做,但您应该阅读它并理解为什么建议这样做,然后再将其视为不必要的。

于 2009-02-25T03:06:01.923 回答
16

MSFT 文档中关于一次性模式存在一些偏见。您应该实施 IDisposable 有两个原因:

  1. 你有一个实现 IDisposable 类型的字段
  2. 你有一个终结者。

案例 1 在大多数代码中很常见。案例 2 在 Microsoft 编写的代码中非常常见,它们是围绕非托管资源编写托管包装器的代码,它们需要最终确定。但是在您的代码中应该非常少见。毕竟,您已经拥有了所有这些不错的 .NET 类来为您完成繁琐的工作。你只需要调用他们的 Dispose() 方法。

只有案例 2 需要一次性模式。微软需要大量使用它。大多数时候你只需要简单的 Dispose() 。

于 2009-02-25T04:52:28.207 回答
5

除了其他很好的答案之外,您可能还想查看这些文章:

于 2009-02-25T07:05:39.493 回答
4

带有布尔处理的附加方法来自某处的框架设计指南。它只是一种模式,允许您的类让 dispose 方法能够被多次调用而不会引发异常。它不是绝对需要的。从技术上讲,您可以在 dispose 方法中执行此操作。

于 2009-02-25T03:03:37.330 回答
1

只是为了扩展其他人所说的话:出于性能原因,这不仅仅是你不需要“复杂的处置”,而是你实际上并不想要它。

如果你走“复杂的处置”路线,并实现一个终结器,然后忘记显式处置你的对象,你的对象(以及它引用的任何东西)将在它真正被处置之前经历额外的 GC 生成(因为它必须挂在一个CLR 有更多时间调用终结器)。这只会导致您不需要的更多内存压力。此外,在整个对象堆上调用终结器具有不小的成本。

所以避免,除非你(或你的派生类型)有非托管资源。

哦,当我们在这个领域时:你的类上处理来自其他人的事件的方法在你的类被释放后被调用时必须是“安全的”。最简单的方法是,如果该类已被释放,则只执行无操作。请参阅http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

于 2010-02-08T01:03:08.773 回答
1

它为您提供的一件事是能够在 Dispose() 中完成与最终确定无关的工作,并且仍然可以清理非托管资源。

在终结器中对除“你自己”之外的托管对象执行任何操作都非常......不可预测。这大部分是由于您的终结器将在您的 AppDomain 的第 2 阶段以非确定性方式关闭时被调用 - 因此当您的终结器被调用时,您仍然引用的对象极有可能已经被敲定。

将 Dispose 和 finalizer 调用调度到同一方法允许您共享关闭代码,而布尔参数允许您跳过托管清理(如果有)。

此外,该方法的虚拟性为继承者添加他们自己的清理代码提供了一种简单的方法,从而减少了无意中没有调用您的代码的风险。

于 2010-02-08T01:56:59.383 回答
1

如果一个类实现并且派生类需要添加额外的逻辑,则该类必须公开派生类可以链接到的IDisposable.Dispose()某种方法。Dispose由于某些类可能在没有公共方法的情况下实现IDisposable.Dispose()Dispose()因此拥有一个将protected在所有实现中都存在的虚拟方法很有用IDisposable,无论它们是否具有公共Dispose方法。在大多数情况下,该bool参数并没有真正的意义,但应该被认为是一个虚拟参数,以使该参数protected virtual Dispose(bool)具有与 may-be-or-maybe-not-public 不同的签名Dispose()

不使用 a 的protected virtual Dispose(bool)类将要求派生类以不同于约定的方式处理其清理逻辑。某些语言(如 C++/CLI)只能扩展IDisposable遵循该约定的实现,可能无法从非标准实现派生类。

于 2017-02-14T17:38:47.997 回答