Implementing a Dispose Method
A type's Dispose method should release all the resources that it owns. It should also release all resources owned by its base types by calling its parent type's Dispose method. The parent type's Dispose method should release all resources that it owns and in turn call its parent type's Dispose method, propagating this pattern through the hierarchy of base types. To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.
Important |
|---|
| C++ programmers should not use this topic. Instead, see Destructors and Finalizers in Visual C++. In the .NET Framework version 2.0, the C++ compiler provides support for implementing deterministic disposal of resources and does not allow direct implementation of the Dispose method. |
A Dispose method should call the GC.SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, GC.SuppressFinalize prevents its Finalize method from being called. Remember that executing a Finalize method is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method.
Note |
|---|
| The code example provided for the System.GC.KeepAlive(System.Object) method shows how aggressive garbage collection can cause a finalizer to run while a member of the reclaimed object is still executing. It is a good idea to call the KeepAlive method at the end of a lengthy Dispose method. |
The purpose of the following code example is to illustrate the recommended design pattern for implementing a Dispose method for classes that encapsulate unmanaged resources. This pattern is implemented throughout the .NET Framework.
Resource classes are typically derived from complex native classes or APIs and must be customized accordingly. Use this code pattern as a starting point for creating a resource class and provide the necessary customization based on the resources you are encapsulating. You cannot compile this sample and use it directly in an application.
In this example, the base class BaseResource implements a public Dispose method that can be called by users of the class. It in turn calls the method virtual Dispose(bool disposing) (virtual Dispose(disposing As Boolean) in Visual Basic). Either true or false is passed depending upon the identity of the caller. The appropriate cleanup code for the object is executed in the virtual Dispose method.
Dispose(bool disposing) executes in two distinct scenarios. If disposing equals true, the method has been called directly or indirectly by a user's code and managed and unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from inside the finalizer and only unmanaged resources can be disposed. When an object is executing its finalization code, it should not reference other objects, because finalizers do not execute in any particular order. If an executing finalizer references another object that has already been finalized, the executing finalizer will fail.
The base class provides a Finalize method or destructor as a safeguard in the event that Dispose is not called. The Finalize method calls the Dispose method that takes parameters, passing false. You should not re-create Dispose clean-up code within the Finalize method. Calling Dispose(false) is optimal for code readability and maintainability.
The class MyResourceWrapper illustrates how to derive from a class that implements resource management using Dispose. MyResourceWrapper overrides the virtual Dispose(bool disposing) method and provides clean-up code for the managed and unmanaged resources that it creates. MyResourceWrapper also calls Dispose on its base class BaseResource to make sure that its base gets the opportunity to clean up properly. Note that the derived class MyResourceWrapper does not have a Finalize method or a Dispose method without parameters, because it inherits them from the base class BaseResource.
Note |
|---|
| The protected Dispose(bool disposing) method in this example does not enforce thread safety because the method cannot be called from a user thread and a finalizer thread at the same time. In addition, a client application using the BaseResource should never allow multiple user threads to call the protected Dispose(bool disposing) method at the same time. An application or class library should be designed to allow only one thread to own the lifetime of a resource and to call Dispose when the resource is no longer needed. Depending on the resource, unsynchronized thread access when disposing of resources can pose a security risk. Developers should carefully review their code to determine the best approach to enforcing thread safety. |
Implementing a Close Method
For types where calling a Close method is more natural than calling a Dispose method, add a public Close method to the base type. The Close method in turn calls the Dispose method without parameters, which performs the proper cleanup operations. The following code example illustrates a Close method.
Important