VB.NET - 在实现IDisposable时,是否应该添加Finalize方法?

7
在Visual Studio中,当我输入"Implements IDisposable"这一行时,IDE会自动添加以下内容:
  • disposedValue成员变量
  • Sub Dispose() Implements IDisposable.Dispose
  • Sub Dispose(ByVal disposing As Boolean)
Dispose()应该保持不变,并且清理代码应该放在Dispose(disposing)中。
然而,Dispose Finalize模式也建议您覆盖Sub Finalize()以调用Dispose(False)。为什么IDE没有添加这个呢?我必须自己添加它吗,还是它隐含地被调用了? 编辑:有什么想法,为什么IDE自动添加80%所需的内容却遗漏了Finalize方法?这种功能的整个意义不就是帮助你不要忘记这些东西吗? 编辑2:谢谢大家的出色答案,现在这一切都很清楚了!
4个回答

11

如果您确实持有不受垃圾回收自动清理的非托管资源,并在Dispose()中清理这些资源,则应在Finalize()中执行相同操作。

如果您为其他原因实现IDisposable,则无需实现Finalize()。

基本问题是:如果没有调用Dispose()并且您的对象被垃圾回收,是否会发生内存泄漏?如果是,则应实现Finalize。如果不是,则不需要。此外,应避免仅因为“更安全”而实现Finalize。具有自定义终结器的对象可能需要两次垃圾回收才能释放它们的内存--一次将其放入挂起终结器队列,另一次才真正释放它们的内存。


1
实现“Dispose”并不意味着您也应该实现finalizer。您可以在不需要finalizer的情况下,在“Dispose”方法中释放未托管的资源。如果必须实现finalizer,那么您的实际清理逻辑应该在一个单独的函数中,它被“Dispose”和“finalize”调用。 - Scott Dorman
1
这是不正确的。如果您仅依赖于Dispose()来释放非托管资源,那么在未调用Dispose的情况下,内存将会泄漏。这正是finalizer存在的原因。 - Laurent
1
不确定为什么我之前没有回复Scott的评论——可能是没注意到,但Laurent是对的——如果您的Dispose正在清理非托管资源,则需要Finalize以确保安全。不要因为懒而省略它。 - Jonathan Rupp

3

没有非托管资源需要清理,因此您不需要使用Finalize。

大多数情况下,类是可处理的原因是它保持对其他托管IDisposable对象的引用。在这种情况下,不需要也不希望有Finalize方法。


您可以在Dispose方法中释放非托管资源,而无需使用终结器。 - Scott Dorman
你可以这样做,但如果没有调用Dispose方法,即使没有Finalize方法,你也可能会泄漏内存。 - Matt Howells

2
Implements IDisposable

Public Overloads Sub Dispose() Implements IDisposable.Dispose

    Dispose(True)
    GC.SuppressFinalize(Me)

End Sub

Protected Overloads Sub Dispose(ByVal disposing As Boolean)

    If disposing Then
        ' Free other state (managed objects).
    End If
    ' Free your own state (unmanaged objects).
    ' Set large fields to null.
End Sub

Protected Overrides Sub Finalize()

    Dispose(False)
    MyBase.Finalize()

End Sub

3
单独的代码块并不十分有用。尝试更具建设性地提供一些代码,包括简短的描述和提供代码的原因。 - Jake Edwards

1

正如其他人所说,除非您直接持有未托管的资源,否则不需要实现终结器。此外,假设您正在使用 .NET 2.0 或更高版本,则通常不需要实现终结器,因为通常可以使用 SafeHandle 来包装您的未托管资源。

我曾经写过一篇相当长的博客文章,介绍了 IDisposable 和终结器的背景和实现,如果您对此还不是完全清楚,那么这篇文章可能值得一读。


您可以在Dispose方法中释放非托管资源,而无需使用finalizer。 - Scott Dorman
是的,这就是IDisposable模式的全部意义。但是如果人们忘记调用Dispose,那么终结器会作为保护措施最终将它们清理干净,因为它是由运行时调用的,不可遗忘。 - Greg Beech

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接