Export (0) Print
Expand All
26 out of 38 rated this helpful - Rate this topic

Implementing a Dispose Method

The pattern for disposing an object, referred to as a dispose pattern, imposes order on the lifetime of an object.

A type's Disposemethod 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.

There is no performance benefit in implementing the Dispose method on types that use only managed resources (such as arrays) because they are automatically reclaimed by the garbage collector. Use the Dispose method primarily on managed objects that use native resources and on COM objects that are exposed to the .NET Framework. Managed objects that use native resources (such as the FileStream class) implement the IDisposable interface.

Important noteImportant Note:

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 SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, 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.

The code example provided for the GC.KeepAlive 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 following code example shows the recommended design pattern for implementing a Dispose method for classes that encapsulate unmanaged resources.

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.

using System;
using System.IO;

class Program
{

    static void Main()
    {
        try
        {
            // Initialize a Stream resource to pass  
            // to the DisposableResource class.
            Console.Write("Enter filename and its path: ");
            string fileSpec = Console.ReadLine();
            FileStream fs = File.OpenRead(fileSpec);
            DisposableResource TestObj = new DisposableResource(fs);

            // Use the resource.
            TestObj.DoSomethingWithResource();

            // Dispose the resource.
            TestObj.Dispose();

        }
        catch (FileNotFoundException e)
        {
            Console.WriteLine(e.Message);
        }
    }
}


// This class shows how to use a disposable resource. 
// The resource is first initialized and passed to 
// the constructor, but it could also be 
// initialized in the constructor. 
// The lifetime of the resource does not  
// exceed the lifetime of this instance. 
// This type does not need a finalizer because it does not 
// directly create a native resource like a file handle 
// or memory in the unmanaged heap. 

public class DisposableResource : IDisposable
{

    private Stream _resource;  
    private bool _disposed;

    // The stream passed to the constructor  
    // must be readable and not null. 
    public DisposableResource(Stream stream)
    {
        if (stream == null)
            throw new ArgumentNullException("Stream in null.");
        if (!stream.CanRead)
            throw new ArgumentException("Stream must be readable.");

        _resource = stream;

        _disposed = false;
    }

    // Demonstrates using the resource.  
    // It must not be already disposed. 
    public void DoSomethingWithResource() {
        if (_disposed)
            throw new ObjectDisposedException("Resource was disposed.");

        // Show the number of bytes. 
        int numBytes = (int) _resource.Length;
        Console.WriteLine("Number of bytes: {0}", numBytes.ToString());
    }


    public void Dispose() 
    {
        Dispose(true);

        // Use SupressFinalize in case a subclass 
        // of this type implements a finalizer.
        GC.SuppressFinalize(this);      
    }

    protected virtual void Dispose(bool disposing)
    {
        // If you need thread safety, use a lock around these  
        // operations, as well as in your methods that use the resource. 
        if (!_disposed)
        {
            if (disposing) {
                if (_resource != null)
                    _resource.Dispose();
                    Console.WriteLine("Object disposed.");
            }

            // Indicate that the instance has been disposed.
            _resource = null;
            _disposed = true;   
        }
    }
}
Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.