HomeDigital EditionSearch Dotnet Cd
ASP.NET C# Certification Exams The CLI Data Access Editorials Extending .NET Fundamentals Interoperability Interviews Migrate Mobile .NET Mono .NET Interface Object-Oriented Programming Open Source Optimization Product/Book Reviews Security Source Code UML Visual Studio .NET

Unmanaged resources are expensive. Therefore, you can't afford to have managed objects that encapsulate unmanaged resources lying dormant in memory waiting for the garbage collector to finalize them. This article shows library developers how to provide an interface to such objects so that they can be finalized at will.

In the Common Language Runtime (CLR), an object is constructed using the newobj Common Intermediate Language (CIL) instruction and destroyed by the garbage collector when all references to it have been lost. Construction of an object involves the allocation of memory and the initialization of the object state (by calling the constructor). Destruction of an object involves the tearing down of its state (by calling the finalizer) and freeing the allocated memory.

The garbage collector is a dedicated low-priority thread that runs periodically and destroys all unreferenced objects, but exactly when the garbage collector will run is not known. This behavior is called nondeterministic finalization.

A garbage collection can be explicitly invoked by using the static System.GC.Collect method. However, this is not advisable because garbage collection is an expensive operation, so it should be left to the system to decide when to invoke it.

Now imagine an object that encapsulates some unmanaged resource. From the time all references to this object are lost to the time the garbage collector finalizes it, the unmanaged resource will lie around unused. This unmanaged resource could be a database connection, a file handle, a bitmap, or something else that is critical in the context of the application. Ideally, such an object should provide the interface to free up the encapsulated unmanaged resource after it is no longer needed. This is what the Dispose pattern does - it facilitates deterministic finalization.

The Dispose pattern allows library developers to provide functionality to their classes to free up any encapsulated unmanaged resources. The .NET Framework Base Class Library provides the foundations for implementing the Dispose pattern through the IDisposable interface.

The Dispose pattern is used extensively in the .NET Framework base class library. Classes such as System.IO.TextReader, System.Drawing.Bitmap, and System.Data.SqlClient.SqlConnection implement the Dispose pattern. They do so because they encapsulate unmanaged resources. For instance, the System.Data.SqlClient. SqlConnection class encapsulates a database connection. If it did not implement the Dispose pattern, there would be no way for developers to close the connections after use. This would leave the connection open until the garbage collector ran. Given the nondeterministic behavior of the garbage collector, it is possible that at times the connection pool will not have any more connections to serve.

The IDisposable Interface
The IDisposable interface is found in the System namespace. It declares a single method, Dispose, which takes no parameters and returns void.

public interface IDisposable
{
void Dispose ();
}

Implementing IDisposable
A class that encapsulates unmanaged resources can implement IDisposable in the following manner:

  • Declare a private Boolean variable that tracks whether or not the object has been disposed.

    private bool disposed = false;

  • Implement a protected Dispose method that takes a Boolean parameter. In this method, free up all unmanaged resources. If the parameter passed is true, call Dispose on member fields that encapsulate unmanaged resources. Set disposed to true to indicate if the object has been disposed (see Listing 1).

    Notice that the first if condition checks whether or not the object has been disposed.

    If the object has been disposed previously, the method returns without doing anything. This way, Dispose can be called on an object any number of times without any problem.

  • Implement the IDispose.Dispose method (the public Dispose). In it, call the protected Dispose, passing it true. Since the object has been disposed, call GC.SupressFinalize, passing this as the parameter to prevent the finalizer from being called when the garbage collector runs.

    public void Dispose ()
    {
    Dispose (true);
    GC.SuppressFinalize (this);
    }

    GC.SuppressFinalize prevents an object that has been disposed from being finalized again by the garbage collector. It also helps with optimization because finalization is an expensive operation, as well as redundant in this case.

  • Implement the finalizer (using the C# destructor syntax) - which overrides the Finalize method provided by Object. Call the protected Dispose and pass it false.

    ~UnamangedResourceContainer ()
    {
    Dispose (false);
    }

  • For all other methods and properties, check if disposed is true. If yes, throw an ObjectDisposedException, otherwise continue with the normal processing.

    public void DoSomething ()
    {
    if (disposed)
    throw ObjectDisposedException ();
    // ...
    }

    Inheriting from a Class That Implements IDisposable
    If your class is inheriting a class that already implements IDisposable, all you need to do is override the protected Dispose method, as shown in Listing 2 .

    The finalizer and the public Dispose that are inherited from the base class are not overridden.

    Domain-Specific Disposing
    The Dispose method needs to be provided by any class that implements the IDisposable interface. However, in certain cases a domain-specific method name may be more semantically appropriate. For example, a class that abstracts operating system processes may need a method called Kill instead of Dispose. In such a case we can implement a public Kill method too. The Kill method calls the public Dispose method.

    public void Kill ()
    {
    Dispose ();
    }

    Conclusion
    In this article we have seen that the management of system resources is very important for the proper functioning of an application. The CLR takes the error-prone task of memory management away from the developer. Also, the System.Object class provides the Finalize method for developers to override in their classes for other resource cleanup routines. This method is called by the garbage collector.

    Since we don't know when the garbage collector will run, chances are that idle resources will hang around in memory when they could be used some other place in the application. To alleviate this problem, the .NET Framework class library provides us with the IDisposable interface, which when implemented provides a way to free the unmanaged resources as soon as they are no longer needed. I hope I was able to show you something useful in this article. Happy programming!

    Resources

  • MSDN TV: Resource Management with the CLR: The IDisposable Pattern: http://msdn.microsoft.com/msdntv/episode.aspx? xml=episodes/en/20030501CLRBA/manifest.xml
  • Implementing Finalize and Dispose to Clean Up Unmanaged Resources: http://msdn.microsoft.com/library/en-us/cpgenref/ html/cpconfinalizedispose.asp

    SIDEBAR

    Tips & Tricks

  • Override System.Object.Finalize only if your class wraps some unmanaged resource.
  • Don't implement the dispose pattern if your class does not have a finalizer.
  • Don't forget to call System.GC.SuppressFinalize after an object is disposed.
  • When finalizing, don't call Dispose on any managed object because it may have already been destroyed by the garbage collector.

    About The Author
    Mujtaba Syed is a software architect with Marlabs Inc. He is an MCSD in .NET (early achiever certificate) and an MCAD in .NET (charter member). He has six years of software architecting and developing experience, half of which were focused on .NET. mujtaba@marlabs.com

    
    
    
    Listing 1
    
    	protected void Dispose (bool disposing)
    	{
    		if (!disposed)
    		{
    			if (disposing)
    			{
    		/*
    		Call dispose on all member fields which
    		encapsulate unmanaged resources...
    		*/
    			}
    
    			// Free up unmanaged resources...
    
    			disposed = true;
    		}
    	}
    
    
    
    Listing 2
    
    protected void Dispose (bool disposing)
    {
    	if (!disposed)
    	{
    		if (disposing)
    		{
    			/*
    			Call dispose on all member fields which
    			encapsulate unmanaged resources...
    			*/
    		}
    
    		// Free up unmanaged resources...
    
    		base.Dispose (disposing);
    
    		disposed = true;
    	}
    
    }
    
    

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.

      E-mail: info@sys-con.com