There seems to be some confusion in the sadeveloper forums about the Dispose pattern, so I thought I look at it in a bit of detail.
Deterministic Finalization
Deterministic Finalization is something that C++, Pascal and similar languages have. What this means is that when you decide that you're finished with something it is cleaned up immediately. The delete keyword in C++ is used for this purpose, it will call any destructors of the object, and then release the memory that the object uses. In the vast majority of cases the destructors do nothing important or do not even exist. In such cases all that happens is that memory is freed. However, it is very common for C++ programmers to forget to delete objects, resulting in memory leaks.
This is particularly the case when an object is used by multiple parts of the program. Since there is no clear "owner" for the object it is difficult to determine who should delete it, resulting in dangling pointers (pointers which point to objects which no longer exist) and memory leaks. To resolve this, many schemes have been attempted, such as auto_ptr<T> and the Boost Libraries shared_ptr<T>.
Well, given that memory is a much more abundant resource than it used to be, the question has to be asked as to why the deletion happens immediately when the object is no longer needed? Freeing up memory can be a quite expensive operation, and many optimizations in C++ involved putting the freeing code outside a loop rather than within it, where perhaps it made more sense, but was just too inefficient.
Garbage collected languages like VB.NET, C# and Java do not delete the object when it is no longer in use, they instead just stop pointing to it. Intermittently the garbage collection will run, which determines which objects are no longer pointed to and deletes them. This is a gross simplification, but good enough for our purposes. If you want more information I suggest you Read Jeffrey Richters articles Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework and Garbage Collection—Part 2: Automatic Memory Management in the Microsoft .NET Framework.
What this means is that the deleting of the object (it's finalization) no longer happens exactly when the object is no longer needed (i.e. is not deterministic). However, the reality is that with schemes such as auto_ptr finalization was pretty tricky to nail down. One would have to study the program very carefully indeed to work out where the object would be deleted. So whilst the finalization was deterministic, it was very difficult for a human to figure out.
Brian Harry, a developer at Microsoft says
[...] we have watched (and helped) hundreds of thousands of lines of code be written without deterministic finalization. Now I am convinced that substantial programs can be reasonably written and debugged without the system providing any automatic support. That said, I fully agree that it would be better if the system/language provided additional support. Without it, you must build the behavior into the contract of the objects (like calling the Dispose method).
Disposing
However, there is one big advantage of deterministic finalization. If the object holds some very expensive resource, such as a handle to a commonly used file, or a database connection, then when it is finalized these resources will be released immediately. In other words, the resource will be released as soon as it is no longer in use. With garbage collection however this is no longer the case, the resource will be released at some point after it is no longer in use.
Quite frankly, in many cases, this is just not good enough. So, the .NET Framework introduces the IDisposable interface. This interface has only one method Dispose, which, when called, is meant to release any expensive resource the object may have. IDisposable should only be implemented by objects with such expensive resources.
The Dispose method is called, usually by the creator of the object, when it is finished with the object. It then immediately frees up the expensive resource, meaning that all that remains of the object is it's memory contents, which will be tidied up automatically by the garbage collector. IDisposable is a way to get what is, to all intents and purposes, deterministic finalization in a garbage collected object.
Performance
Many purists will claim that deterministic finalization, where the expensive resources and the memory are disposed of at the same time, is much more efficient than a garbage collected solution. However, it appears that reality does not completely back up their claims. Garbage collection is very efficient at allocations, far more so than most implementations of malloc since the garbage collector defragments the heap from time to time. malloc does a similar operation, coalescing contiguous free blocks, but it cannot truly defragment because it cannot move in-use memory. Managed systems like .NET and Java can.
So, whilst malloc and it's ilk face a gradually declining memory performance, managed environments have very quick memory performance, coupled with periods of extreme slowness (no execution whatsoever) during a garbage collection. .NET uses generational garbage collection to help speed this process up. Also, keep in mind that unless there is significant memory pressure, the garbage collector will tend to run when the app is largely idle anyway. From wikipedia:
[...] the garbage collector allows the runtime system to amortize allocation and deallocation operations in a potentially advantageous fashion
So in a best-case scenario (large memory, periods of idle) a garbage collected system can spend much less time dealing with memory than a non-garbage collected one. In a worst-case scenario (small memory, 100% CPU), the garbage collector would be likely be slightly slower than a non-garbage collected environment.
However, garbage collection, since it is not deterministic, cannot be easily used in embedded or real-time systems.
Conclusion
With garbage collections benefits, the only real penalty is this deterministic finalization thing, and IDisposable gives us something that approximates this. However, there is a big problem with this: what if the person using your class doesn't call Dispose? Then the clean-up of the resources doesn't happen. So we need a way to ensure that it will always happen. We use the appropriately named Finalize method in .NET. I will address this in my next article.
Next: The Dispose Pattern - Finalizers and Dispose