Given all the benefits of the Garbage Collector (GC) in .NET, the IDisposable/Dispose pattern is a necessary evil. It does make the code more complicated, harder to manage, and more error-prone. However, if you want to rely solely on finalizers to release resources, your application isn't going to fly.
Releasing resources (database connections, handles to open files, blocks of memory, etc.) as soon as they are no longer needed is prudent. Also, dropping the references to other objects is a great idea, because it helps the GC reclaim unused memory more efficiently. For the GC, the more null references, the better.
To reiterate, the Dispose() method should be used to:
- Release managed resources (in the realm of CLR);
- Release unmanaged resources (in the native realm);
- Drop references (set them to null).
Thus, Dispose() may also be used to:
- Cancel any pending async operations.
- To warn if the Dispose() method hasn't been called (via asserting or logging).
There is an IDisposable pattern (C# .NET) posted on MSDN. I personally prefer the following variation:
using System;
using System.Diagnostics;
namespace MyProject
{
class MyClass:
IDisposable
{
~MyClass()
{
DisposeOfUnmanagedResources();
// should have called Dispose!
Debug.Assert(false);
}
public void Dispose()
{
DisposeOfUnmanagedResources();
// release managed resources
GC.SuppressFinalize(this);
}
private void DisposeOfUnmanagedResources()
{
// release unmanaged resources
}
}
}
(The sample above was formatted using http://www.manoli.net/csharpformat/)
Compared to the original pattern on MSDN, here:
- DisposeOfManagedResources()/DisposeOfUnmanagedResources() replace the ambiguous Dispose(bool) method;
- The finalizer ~MyClass() would raise an assertion (in Debug builds) if the user of MyClass hasn't called Dispose().
No comments:
Post a Comment