views:

125

answers:

6

Based on the documentation (MSDN: link), it is clear that one should use the IDisposable pattern when implementing a finalizer.

But do you need to implement a finalizer if you implement IDisposable (so as to provide a deterministic way of disposing the object), and you dont have any unmanaged resources to clean up?

As I see it, if the class has only managed resources and if you dont call Dispose, the managed resources will automatically get cleaned up by the GC and hence no need to implement the finalizer. Am I wrong?

Also, what if I am using my Dispose method to clean up event handlers. As Dispose wont automatically get called by the GC, should I implement a Finalizer, to ensure that eventhandlers get unwired?

+4  A: 

You should not add a finalizer unless you have unmanaged resources.

A class that owns managed disposable resources but not unmanaged resources should implement the full Dispose pattern, but not have a finalizer.

If the class is not sealed, it should call GC.SuppressFinalize(this) in its Dispose() method in case an inherited class adds a finalizer.

SLaks
And what if that inherited class also adds an unmanaged resource?
Henk Holterman
@Henk: That's why it would add a finalizer. (And override `Dispose(bool)`)
SLaks
I still don't see why a base class Dispose should mess with SupressFinalize at all. If it does, a derived Dispose cannot safely call base.Dispose().
Henk Holterman
@Henk: Huh? What are you talking about? `SuppressFinalize` is called by the non-virtual `Dispose()` method, and should be called in any situation. If the derived class adds an unmanaged resources, it should clean it up in `Dispose(bool)`, and add a finalizer which calls `Dispose(false)`. If the normal `Dispose` method is called, the unmanaged resources get cleaned up, so the finalizer should be suppressed.
SLaks
About your last paragraph, Suppress when not sealed.
Henk Holterman
Your answer contradicts adrianBanks answer - so who is right?
Rajah
No I don't. I'm not saying the the base class should write a finalizer. It should just suppress it. He didn't mention that at all.
SLaks
Sources: http://msdn.microsoft.com/en-us/library/ms244737%28v=VS.100%29.aspx http://msdn.microsoft.com/en-us/magazine/cc163324.aspx
SLaks
I would say you should call GC.SuppressFinalize(this) in Dispose() in a finalisable class whether sealed or not. That said, I'd make it sealed anyway, and not suffer the Dispose(bool) anti-pattern.
Jon Hanna
@Jon: If the class is sealed and has no finalizer, there is no point in calling `SuppressFinalize`.
SLaks
Oh sorry. Misread and thought that was about the case where there is a finaliser.
Jon Hanna
SLaks, right. I missed who was virtual.
Henk Holterman
@Slaks: Given the existence of SafeHandle, is there any reason to expect derived classes to own unmanaged resources? If a class holds references to many other objects, adding a finalizer in a derived class would seem like a bad idea.
supercat
A: 

If you only have managed resources, then you don't need to implement IDisposable at all. IDisposable is intended for cleaning up things beyond the GC's domain, such as native handles, database connections, etc.

If your control contains controls that implement IDisposable and they must release native resources, then you still need to implement the IDisposable pattern and give your child controls a chance to dispose.

The reason for calling Dispose() in the finalizer is as a last resort, if the object was not properly disposed, the GC will do it as a last ditch effort.

Matt Greer
You're missing the case where your class holds references to managed resources that implement IDisposable. Then you should have a Dispose that calls Dispose on these objects
Isak Savo
@Isak I addressed that in paragraph two.
Matt Greer
Ok,i see that now. Your first paragraph is a bit misleading though - I'd consider a class implementing Idisposable to be managed.
Isak Savo
A: 

Yes, if you have only managed resources, they will be cleaned up by the GC when Garbage collection occurs (and there isn't any living references pointing to them)

But in this case, why do you need to implement IDisposable on your type? I mean, you seem to consider that in your case, not disposing your object is not a big issue, then why would someone dispose them?

You should also note that there is a performance penality with garbage collection while using Finalizers: Any object with a finalizer will escape the first GC pass, which will degrade GC efficiency quite a bit if these objects are short lived.

During the first garbage collection during which the object should be cleaned up, it won't, in order to execute the finalizer. The object will then be considered as long lived by the GC, even if it should already be cleaned.

Maupertuis
+4  A: 

No, you do not need to implement a finalizer if you have a class that implements IDisposable (that is if you have implemented the pattern correctly, and that you only have managed resources to dispose of).

(If you do, it can actually affect the lifetime of your object, as objects with finalizers get added to the finalization queue in the GC and can live longer than they need to - this can be a problem if your objects are large.)

adrianbanks
Your answer contradicts SLaks answer, so who is right?
Rajah
@Rajah: Our answers do not contradict. However, I am right; see http://msdn.microsoft.com/en-us/library/ms244737%28v=VS.100%29.aspx and http://msdn.microsoft.com/en-us/magazine/cc163324.aspx
SLaks
@Rajah: The answers do not contradict. I answered your question: "do you need to implement a finalizer if you implement IDisposable...and you dont have any unmanaged resources to clean up". The answer is that you do not need to.
adrianbanks
Based on all the comments on this question, I have written a post http://blog.aggregatedintelligence.com/2010/10/idisposable-and-finalizers.html.
Rajah
A: 

I have never had the need to implement a finalizer. As you know, it gives the object a chance to do whatever it needs prior to GC. All resources should be freed up in the dispose method

Bryce Fischer
Unmanaged resources must be cleaned by the finalizer (and Dispose; see the pattern)
SLaks
That's right.. sorry, was assuming unmanaged...
Bryce Fischer
errr Managed.,..
Bryce Fischer
What reasons exist for any newly-authored classes other than SafeHandle to hold unmanaged resources? Obviously classes which predate SafeHandle must do so, but is there any for newly-authored classes to do so?
supercat
+1  A: 
  1. No, you are correct, if your object holds an object that holds an unmanaged resource then you should implement IDisposable so that you can call its Dispose on your Dispose, but you don't need a finaliser as its finaliser will deal with that matter.

  2. Indeed, trying to do anything with a finalisable member from in a finaliser is fraught, as which order the finalisers will run is not deterministic, so you can get some nasty bugs if you try to do this.

  3. As a rule it's much better to have a class either hold 1 or 0 unmanaged resources. And if it has 1 unmanaged resource, it should have as little other state as needed to deal with it (i.e. no other disposable members). SafeHandle is a good way of dealing with this. If a class needs to deal with several unmanaged resources it should do so by handling said resources through these handler classes. Then a finaliser & IDisposable becomes easy; either you have the sole unmanaged resource to deal with in both (suppress the finaliser if dispose is called) or you only need IDisposable.

Because having to deal with unmanaged resources directly is relatively rare, the chances are you will never have to write a finaliser (I think I have done so once, in real code). Because sensible people don't do much else in classes that handle unmanaged resources, the whole Dispose(bool) thing is unnecessary too.

Jon Hanna