Dispose and Finalizable patterns
For the majority of the objects that your app creates, you can rely on .NET's garbage collector to handle memory management. However, when you create objects that include unmanaged resources, you must explicitly release those resources when you finish using them in your app. The most common types of unmanaged resource are objects that wrap operating system resources, such as files, windows, network connections, or database connections. Although the garbage collector is able to track the lifetime of an object that encapsulates an unmanaged resource, it doesn't know how to release and clean up the unmanaged resource.
If your types use unmanaged resources, you should do the following:
Implement the dispose pattern. This requires that you provide an IDisposable.Dispose implementation to enable the deterministic release of unmanaged resources. A consumer of your type calls Dispose when the object (and the resources it uses) is no longer needed. The Dispose method immediately releases the unmanaged resources.
Provide for your unmanaged resources to be released in the event that a consumer of your type forgets to call Dispose. There are two ways to do this:
Use a safe handle to wrap your unmanaged resource. This is the recommended technique. Safe handles are derived from the System.Runtime.InteropServices.SafeHandle class and include a robust Finalize method. When you use a safe handle, you simply implement the IDisposable interface and call your safe handle's Dispose method in your IDisposable.Dispose implementation. The safe handle's finalizer is called automatically by the garbage collector if its Dispose method is not called (better solution for most cases).
—or—
Override the Object.Finalize method. Finalization enables the non-deterministic release of unmanaged resources when the consumer of a type fails to call IDisposable.Dispose to dispose of them deterministically. However, because object finalization can be a complex and error-prone operation, we recommend that you use a safe handle instead of providing your own finalizer.
Implementing a Dispose method
The Dispose() overload
The
Dispose
method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.SuppressFinalize has no effect. Note that the actual work of releasing unmanaged resources is performed by the second overload of theDispose
method.The Dispose(Boolean) overload
In the second overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is
true
) or from a finalizer (its value isfalse
).The body of the method consists of two blocks of code:
A block that frees unmanaged resources. This block executes regardless of the value of the
disposing
parameter.A conditional block that frees managed resources. This block executes if the value of
disposing
istrue
. The managed resources that it frees can include.
If the method call comes from a finalizer (that is, if disposing is
false
), only the code that frees unmanaged resources executes. Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling thisDispose
overload with a value offalse
prevents the finalizer from trying to release managed resources that may have already been reclaimed.
Implementation Samples:
Base class
DerivedClass
Last updated