11

根据文档(MSDN:链接),很明显在实现终结器时应该使用 IDisposable 模式。

但是,如果您实现了 IDisposable(以便提供一种确定性的方式来处理对象),并且您没有任何非托管资源要清理,您是否需要实现终结器?

如我所见,如果该类只有托管资源并且您不调用 Dispose,则托管资源将自动被 GC 清理,因此无需实现终结器。我错了吗?

另外,如果我使用我的 Dispose 方法来清理事件处理程序会怎样。由于 Dispose 不会自动被 GC 调用,我是否应该实现终结器以确保事件处理程序不连线?

4

6 回答 6

12

不,如果您有一个实现 IDisposable 的类(也就是说,如果您正确实现了该模式,并且您只有托管资源要处置),则不需要实现终结器。

(如果这样做,它实际上会影响对象的生命周期,因为带有终结器的对象会被添加到 GC 中的终结队列中,并且可以比它们需要的寿命更长 - 如果您的对象很大,这可能是个问题。)

于 2010-10-07T14:46:43.933 回答
11

除非您有非托管资源,否则不应添加终结器。

拥有托管一次性资源但不拥有非托管资源的类应该实现完整Dispose模式,但没有终结器。

如果类不是sealed,它应该调用GC.SuppressFinalize(this)它的Dispose()方法,以防继承的类添加终结器。

于 2010-10-07T14:43:26.997 回答
2
  1. 不,你是对的,如果你的对象持有一个持有非托管资源的对象,那么你应该实现 IDisposable 以便你可以在你的 Dispose 上调用它的 Dispose,但你不需要终结器,因为它的终结器会处理这个问题。

  2. 事实上,尝试对终结器中的可终结成员执行任何操作是令人担忧的,因为终结器将运行的顺序不是确定性的,因此如果您尝试这样做,您可能会遇到一些令人讨厌的错误。

  3. 通常,最好让一个类拥有 1 个或 0 个非托管资源。如果它有 1 个非托管资源,它应该有尽可能少的其他状态来处理它(即没有其他可支配成员)。SafeHandle 是处理这个问题的好方法。如果一个类需要处理几个非托管资源,它应该通过这些处理程序类来处理所述资源。然后终结器和 IDisposable 变得容易;要么你有唯一的非托管资源来处理(如果调用 dispose 则抑制终结器)或者你只需​​要 IDisposable。

因为必须直接处理非托管资源相对较少,所以您可能永远不必编写终结器(我想我曾经这样做过,在实际代码中)。因为明智的人不会在处理非托管资源的类中做很多其他事情,所以整个 Dispose(bool) 事情也是不必要的。

于 2010-10-07T14:55:25.457 回答
0

如果您只有托管资源,那么您根本不需要实现 IDisposable。IDisposable 旨在清理 GC 域之外的东西,例如本机句柄、数据库连接等。

如果您的控件包含实现 IDisposable 的控件并且它们必须释放本机资源,那么您仍然需要实现 IDisposable 模式并让您的子控件有机会释放。

在终结器中调用 Dispose() 的原因是作为最后的手段,如果对象没有正确处理,GC 将作为最后的努力去做。

于 2010-10-07T14:44:00.383 回答
0

是的,如果您只有托管资源,垃圾收集发生时它们将被 GC 清理(并且没有任何指向它们的活动引用)

但是在这种情况下,为什么你需要在你的类型上实现 IDisposable 呢?我的意思是,您似乎认为在您的情况下,不处置您的对象不是一个大问题,那么为什么有人会处置它们呢?

您还应该注意,在使用终结器时,垃圾回收会降低性能:任何带有终结器的对象都将逃脱第一次 GC 传递,如果这些对象的生命周期很短,这将大大降低 GC 效率。

在应该清理对象的第一次垃圾回收期间,为了执行终结器,它不会。然后该对象将被 GC 视为长期存在的,即使它应该已经被清除。

于 2010-10-07T14:46:29.360 回答
0

我从来不需要实现终结器。如您所知,它使对象有机会在 GC 之前执行所需的任何操作。应该在 dispose 方法中释放所有资源

于 2010-10-07T14:49:01.963 回答