Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

  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?
  2. Apart from Reflection, how would you figure out if the object has a Finalizer?
  3. 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".

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.

like image 244
Storm Avatar asked Jan 21 '16 09:01

Storm


People also ask

Which of the following option is the correct way to call Dispose from a finalizer?

Dispose() should call Dispose(true) , and the finalizer should call Dispose(false) . If you create an unsealed type that declares and implements the IDisposable interface, you must define Dispose(bool) and call it. For more information, see Clean up unmanaged resources (.

What will happen if we call Dispose () method directly?

The Dispose() methodThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

Does Dispose get called automatically?

By default, the garbage collector automatically calls an object's finalizer before reclaiming its memory. However, if the Dispose method has been called, it is typically unnecessary for the garbage collector to call the disposed object's finalizer.

What is the difference between Dispose () and Finalize ()?

Finalize is the backstop method, called by the garbage collector when it reclaims an object. Dispose is the "deterministic cleanup" method, called by applications to release valuable native resources (window handles, database connections, etc.)


1 Answers

  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?

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. I.e. 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.

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

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 (i.e. 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 (e.g. 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.

  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".

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

like image 195
Peter Duniho Avatar answered Sep 18 '22 05:09

Peter Duniho