在具有终结器的 class 上调用 .Dispose()

Calling .Dispose() on a class that has a Finalizer

根据 Essential C# 6.0 你应该:

AVOID calling Dispose() on owned objects that have a finalizer. Instead, rely on the finalization queue to clean up the instance.

  1. 有人可以详细说明一下吗,因为我不清楚如果我们不从拥有的对象中调用 Dispose 的意义何在?
  2. 除了反射,你如何判断对象是否具有 Finalizer
  3. 除了搜索 API 文档(如果您有权访问它并且它存在) 还是反射?我在网上看到很多关于非常特定类型的问题(MemoryStream / Form / SqlConnection / 等),但我更多地关注 "how to figure it out yourself".

根据 Dispose Pattern 你应该:

CONSIDER providing method Close(), in addition to the Dispose(), if close is standard terminology in the area. When doing so, it is important that you make the Close implementation identical to Dispose and consider implementing the IDisposable.Dispose method explicitly.

但有时你应该用 Form 等调用两者。像“Close and Dispose - which to call?”这样的问题很接近,但除了

之外没有明确的方法

As usual the answer is: it depends. Different classes implement IDisposable in different ways, and it's up to you to do the necessary research.

编辑:这是完整的指导方针,我没有请求复制许可,但因为它是一个指导方针(因此假设它应该是免费共享 public 知识)而不是实际的一部分训练 material,我希望我没有违反任何规则。

Guidelines
DO implement a finalizer method only on objects with resources that are scarce or expensive, even though finalization delays garbage collection.
DO implement IDisposable to support deterministic finalization on classes with finalizers.
DO implement a finalizer method on classes that implement IDisposable in case Dispose() is not invoked explicitly.
DO refactor a finalization method to call the same code as IDisposable, perhaps simply calling the Dispose() method.
DO NOT throw exceptions from finalizer methods.
DO call System.GC.SuppressFinalize() from Dispose() to avoid repeating resource cleanup and delaying garbage collection on an object.
DO ensure that Dispose() is idempotent (it should be possible to call Dispose() multiple times).
DO keep Dispose() simple, focusing on resource cleanup required by finalization.
AVOID calling Dispose () on owned objects that have a finalizer. Instead, rely on the finalization queue to clean up the instance.
AVOID referencing other objects that are not being finalized during finalization.
DO invoke a base class’s Dispose() method when overriding Dispose().
CONSIDER ensuring that an object becomes unusable after Dispose() is called. After an object has been disposed, methods other than Dispose() (which could potentially be called multiple times) should throw an ObjectDisposedException.
DO implement IDisposable on types that own disposable fields (or properties) and dispose of said instances.

  1. Could someone please elaborate on this as I'm not clear on what the point of Dispose is if we're not to call it from owned objects?

没有这本书的全文及其上下文(我没有这本书的副本,也没有很多其他人阅读你的问题),不可能确定它们的意思。但这应该是一本好书,因此我必须假设您引用的文本旨在 与您自己的终结器中的代码相关。 IE。当然你应该正常处理拥有的对象。在您的 Dispose() 方法中。

这是关于如果您的对象没有被妥善处理该怎么办。答案是清理您自己的非托管资源。

与此相关的是,随着 SafeHandle class 的出现(前段时间),您可能根本不需要终结器。相反,将您自己的非托管资源包装在 SafeHandle 子 class 中,并让 class 处理完成。

  1. Apart from Reflection, how would you figure out if the object has a Finalizer?

除了反思之外,您还需要依赖源代码(如果可用)、文档(如果已编写)或对象实现 IDisposable 的简单事实(即做出假设……它是不能保证,但两者之间有很强的相关性。

更重要的是,请注意,因为可以在不使用终结器的情况下正确地实现实现 IDisposable 的对象(例如,如果您使用 SafeHandle,或者如果您实现 IDisposable 只有这样你才能确定性地清理拥有的 IDisposable 个对象),不能保证终结器的存在。

我认为更好的表述方式是 "don't dispose objects in your finalizer"。依赖于 IDisposable 对象本身应该 以某种方式 处理完成其自己拥有的资源这一事实,并且仅关注您自己的对象直接拥有的任何非托管资源 .

  1. How do you figure out when to call Close() / Close() + Dispose() other than searching the API documentation (if you have access to it and it exists) or Reflection? I see a lot of questions around the net for very specific types ( MemoryStream / Form / SqlConnection / etc ) but I'm looking more at "how to figure it out yourself".

你不能。不是没有仔细检查代码。也就是说……

您永远不必同时调用 Close()Dispose()。如果 class 正确实现,两者应该总是等价的。

当然,.NET 中没有任何内容强制。所以不能肯定地说你不需要。但是,如果您处理的是需要两者的类型,那么它的编写很糟糕,并且在其他方​​面也可能被破坏。最好完全避免使用该类型。 :)

当然,正如您所指出的,Form class 在某些情况下 需要您同时调用 Close()Dispose() (在大多数情况下,调用 Close() 实际上就足够了……只是因为他们实现模态对话框的方式很奇怪,所以你得到了规则的例外)。但那是一个非常古老的 API,是在 IDisposable 模式的复杂性的全部含义被真正完全理解之前设计的。人们希望 Microsoft 不会以相同的方式设计 API,如果他们不得不再次这样做的话(事实上,WPF 没有相同的二分法)。

现代实施应该更好地更一致地遵循良好的约定。


附录:

我四处浏览了一下。当然,在 Stack Overflow 上有很多关于 GC、finalization、IDisposable、finalizers 等的文章,但我没有看到任何似乎直接等同于你的问题的文章。这个似乎是最接近的:

Which objects can I use in a finalizer method?

其他可能有用的补充阅读:

When would dispose method not get called?
Why call Dispose()? Memory leak won't occur?
IDisposable and managed resources

当然还有 classic:
Proper use of the IDisposable interface