Dispose and Finalizable patterns
Last updated
Last updated
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 . This requires that you provide an implementation to enable the deterministic release of unmanaged resources. A consumer of your type calls when the object (and the resources it uses) is no longer needed. The 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 . 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 class and include a robust method. When you use a safe handle, you simply implement the interface and call your safe handle's method in your implementation. The safe handle's finalizer is called automatically by the garbage collector if its method is not called (better solution for most cases).
—or—
Override the method. Finalization enables the non-deterministic release of unmanaged resources when the consumer of a type fails to call 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' override. Therefore, the call to the method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to has no effect. Note that the actual work of releasing unmanaged resources is performed by the second overload of the Dispose
method.
The Dispose(Boolean) overload
In the second overload, the disposing parameter is a that indicates whether the method call comes from a method (its value is true
) or from a finalizer (its value is false
).
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
is true
. 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 this Dispose
overload with a value of false
prevents the finalizer from trying to release managed resources that may have already been reclaimed.
Implementation Samples:
Base class
DerivedClass