Calling .Dispose() on a class that has a Finalizer
According to Essential C# 6.0 you should:
AVOID calling Dispose() on owned objects that have a finalizer. Instead, rely on the finalization queue to clean up the instance.
Finalizer
? 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". According to the Dispose Pattern you should:
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.
but there are times when you should call both like with Form
, etc. Questions like "Close and Dispose - which to call?" get close but there's no defined approach apart from
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.
Edit: Here is the full guideline, I haven't asked for permission to reproduce but since it's a guideline (thereby assuming it's supposed to be freely shared public knowledge) and not some part of the actual training material, I'm hoping I'm not breaking any rules.
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.
Without the full text of the book and its context (I don't have a copy of the book, nor may many other people reading your question), it's impossible to say for sure what they mean. But it's supposed to be a good book, and as such I have to assume that the text you're quoted is intended to pertain only to code in your own finalizer. Ie of course you should dispose owned objects normally. In your Dispose()
method.
It's about what to do if your object hasn't been disposed properly. And the answer there is to just clean up your own unmanaged resources.
Related to this is that now, with the advent (some time ago) of the SafeHandle
class, you may not need a finalizer at all. Instead, wrap your own unmanaged resources in a SafeHandle
subclass and let that class deal with finalization.
Apart from reflection, you'd be relying on the source code (if available), the documentation (if written), or simply the fact that the object implements IDisposable
(ie make an assumption…it's not guaranteed, but there's a strong correlation between the two).
More to the point, note that since it is possible to correctly implement an object that implements IDisposable
without using a finalizer (eg if you use SafeHandle
, or if you implement IDisposable
only so that you can deterministically clean up owned IDisposable
objects), the presence of a finalizer is not guaranteed.
I think a better way to word the guidance would be "don't dispose objects in your finalizer". Rely on the fact that an IDisposable
object should itself somehow deal with finalizing its own owned resources, and focus only on any unmanaged resources your own object owns directly .
You can't. Not without inspecting the code carefully. That said…
You should never have to call both Close()
and Dispose()
. The two should always be equivalent, if the class is implemented correctly.
Of course, there's nothing in .NET that enforces that. So it's not possible to say for sure you wouldn't need to. But if you're dealing with a type that requires both, it was poorly written and may be broken in other ways as well. May be best to just avoid using that type altogether. :)
And of course, as you point out, the Form
class in some cases requires you to call both Close()
and Dispose()
(in most cases, calling Close()
is actually sufficient…it's only because of the weird way they implemented modal dialogs that you get the exception to the rule). But that's a very old API, designed before the full implications of the complexities of the IDisposable
pattern were really fully understood. One hopes Microsoft wouldn't design that API the same way today if they had to do it again (and indeed, WPF doesn't have that same dichotomy).
Modern implementations should do a better job of following good conventions more uniformly.
Addendum:
I did a little browsing around. There are, of course, lots of articles about GC, finalization, IDisposable
, finalizers, etc. on Stack Overflow, but I didn't see any that seemed to be directly equivalent to your question. This one seemed the closest though:
Which objects can I use in a finalizer method?
Others that might be useful additional reading:
When would dispose method not get called?
Why call Dispose()? Memory leak won't occur?
IDisposable and managed resources
And of course, the classic:
Proper use of the IDisposable interface
上一篇: 析构函数的区别,配置和终结方法