sharptooth
sharptooth

Reputation: 170479

Do I have to do anything special in the destructor of a class that implements IDisposable?

I have a C# class that implement IDisposable and in my Dispose() implementation I call Dispose() on the subojects that also implement IDisposable.

What about the destructor of the same class? Do I have to do anything special in there?

Upvotes: 0

Views: 197

Answers (3)

supercat
supercat

Reputation: 81115

The C# destructor syntax directs the compiler to override Object.Finalize(). A class which overrides Object.Finalize() is said to have a "finalizer"; all such objects are placed in a special list called the "Finalization Queue" (the term "queue" is perhaps a little strange, since the list has no semantically-relevant ordering) and marked as "finalizable". When a garbage collection is performed, the system starts by tagging all of the objects to which direct or indirect strong references exist outside the finalization queue. The system then examines every finalizable object to see if it has yet been tagged. If it hasn't, it will be marked as "not finalizable", but will be added to a queue called "freachable [eff-reachable] queue". Finally, the system will tag all objects in the freachable queue as "live", discard all untagged objects, and--if the freachable queue is not empty--dispatch a thread to start calling Finalize on all the items contained therein. Note that objects which are in the "freachable queue", and every object to which they hold strong references, will be regarded as "live" until they their Finalize() method has run; since they will have been marked "not finalizable", they will be eligible for garbage collection after that unless either they have been re-marked as "finalizable", or a strong reference to them has been stored in a live object.

Note that a "destructor" or "finalizer" does hasten the destruction of an object--instead, it will give objects that would have been destroyed a reprieve to run their Finalize() method (which, for C# programs, will in turn run the code in the destructor). This may be useful if the object with the finalizer knows of something that (1) needs to happen before the end of the universe, (2) no other object is going to do, and (3) can be safely done within an arbitrary and unknown threading context. Note that an finalizer should seldom be used to call IDisposable.Dispose on other objects. If such objects can handle being disposed from arbitrary threading contexts, they can probably finalize themselves (so their disposal wouldn't meet requirement #2); if they can't handle being disposed from arbitrary threading contexts, they can't be disposed within a finalizer (requirement #3).

Incidentally, Microsoft early on in the development of .net seemed to think that classes which implement IDisposable but do not have finalizers should make provisions so derived classes can add finalizers, and they continue to recommend a Dispose pattern that makes allowances for this. While it can sometimes be useful for a derived class to have an "alarm bell" finalizer which generates some kind of warning if it is called on an object which hasn't been disposed, I would suggest that a class derived from a non-trivial class that don't have a finalizer should not attempt to perform cleanup within a finalize method or destructor. Finalization involves some tricky corner cases which can cause Heisenbugs (unpredictable failures) if not handled perfectly at every step of the inheritance chain. If a base class isn't designed to support reliable finalization cleanup, adding a finalizer to a derived class may break code that would otherwise have worked.

Upvotes: 1

Daniel Renshaw
Daniel Renshaw

Reputation: 34177

I think you mean a finalizer instead of destructor.

Note that a finalizer is quite unusual. It is certainly not true that every disposable object should have a finalizer. Usually, only objects that control non-managed resources (i.e. those acquired outside the control of the CLR) might need a finalizer.

If you definitely do need a finalizer, then, you should call GC.SuppressFinanlize in your dispose method. From the docs for implementing a Dispose method:

A Dispose method should call the SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, SuppressFinalize prevents its Finalize method from being called. Remember that executing a Finalize method is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method.

Please see the GC.SuppressFinanlize documentation for an example pattern that includes a finalizer.

Upvotes: 0

Charleh
Charleh

Reputation: 14012

Nope, as long as you free any resources in the Dispose implementation you are ok. Microsoft recommend that usage of the IDisposable interface is achieved with a using() statement so that the app immediately calls dispose when the object goes out of scope. Sounds like you are doing everything ok - just make sure you try and use using() when using that implementation.

I know sometimes it's not possible and you want the scope to last a little longer, but disposable is usually for working with unmanaged resources so you tend to not have much of a lifetime on these things

Update:

Looks like theres a reason to create a destructor too as someone has posted in their comment :)

You learn something new every day on here :D

Upvotes: 0

Related Questions