Destructor vs IDisposable?

I wrote a fairly in-depth post which should help to explain about finalizers, IDisposable, and when you should use one or the other: http://gregbee.ch/blog/implementing-and-using-the-idisposable-interface

Probably the most relevant part is quoted below:

When you are using unmanaged resources
such as handles and database
connections, you should ensure that
they are held for the minimum amount
of time, using the principle of
acquire late and release early. In C++
releasing the resources is typically
done in the destructor, which is
deterministically run at the point
where the object is deleted. The .NET
runtime, however, uses a garbage
collector (GC) to clean up and reclaim
the memory used by objects that are no
longer reachable; as this runs on a
periodic basis it means that the point
at which your object is cleaned up is
nondeterministic. The consequence of
this is that destructors do not exist
for managed objects as there is no
deterministic place to run them.

Instead of destructors, C# has
finalizers which are implemented by
overriding the Finalize method defined
on the base Object class (though C#
somewhat confusingly uses the C++
destructor syntax ~Object for this).
If an object overrides the Finalize
method then rather than being
collected by the GC when it is out of
scope, the GC places it on a finalizer
queue. In the next GC cycle all
finalizers on the queue are run (on a
single thread in the current
implementation) and the memory from
the finalized objects reclaimed. It’s
fairly obvious from this why you don’t
want to do clean up in a finalizer: it
takes two GC cycles to collect the
object instead of one and there is a
single thread where all finalizers are
run while every other thread is
suspended, so it’s going to hurt
performance.

So if you don’t have destructors, and
you don’t want to leave the cleanup to
the finalizer, then the only option is
to manually, deterministically, clean
up the object. Enter the IDisposable
interface which provides a standard
for supporting this functionality and
defines a single method, Dispose,
where you put in the cleanup logic for
the object. When used within a finally
block, this interface provides
equivalent functionality to
destructors. The reason for finally
blocks in code is primarily to support
the IDisposable interface; this is why
C++ uses simply try/except as there is
no need for a finally block with
destructors.

Leave a Comment