Today’s post is written just to highlight the difference between three different concepts of how objects are managed in a .NET application.
First, let’s start with the most basic: garbage collection. The MSDN topic on garbage collection fundamentals goes into quite a bit of detail and provides some great information. In a nutshell, what happens is that every so often, the system looks for objects that cannot possibly be used anymore because there are no more usable references to them, and reclaims the memory for them so it can be used to hold other objects or to return it to the operating system. It’s the equivalent of a call to free in C, except that the system handles this for you.
Next, let’s talk about finalization. This is simply the capability of objects to have a special method (caller finalizer) that is run when the garbage collector has decided that the object is ready to be collected. Under the covers, the garbage collector builds a queue of these objects and then calls them, possibly from a different thread at a later time.
This is used for cases like the following: let’s say I have a class that uses P/Invoke to call into a Win32 API to open a file, and I store the handle in a field. If I don’t close the file handle at some point, other applications may not be able to use the file. To make sure that at some point the file gets closed, I can write a finalizer for my object to do this.
There’s still a problem with this, though. Garbage collection isn’t constantly running for performance reasons, and we have no idea for how long we may be holding this file handle open. The convention in this case is to have our class implement the Dispose method of the IDisposable interface, and close the handle there. The users of the class need to remember to call this method when they want the resources released. In fact, C# even building the functionality of the using keyword around this method. But again, this is just convention – the .NET garbage collection only knows about whether objects can be reached or not and whether they need to be finalized.
Classes that implement IDisposable may also implement a finalizer, but this isn’t always the case. Typically you only implement the finalizer if you own some resource that needs to be released, but you can always implement IDisposable to "propagate out" the object disposals.
Hopefully this explains some of the differences in a simple way. If you’re thinking of implementing IDisposable on an object or of adding a finalizer, the Implementing Finalize and Dispose to Clean Up Unmanaged Resources topic on MSDN goes into more detail and more practical guidelines on how to do this. Very much worth reading.