Finalizer and IDisposable

2019-01-15 01:45发布

问题:

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?

回答1:

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



回答2:

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.



回答3:

  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.



回答4:

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.



回答5:

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.



回答6:

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