Disposable Base Class
Posted by Dan Rigsby on March 15th, 2008
Many classes are built that implement System.IDisposable, which is a good thing. This pattern makes for a good design to clean up your objects and can be used by the using statement to easily dispose of your objects. This article already assumes that you know the basics of the Dispose Pattern. However sometimes having just a Dispose() method isn’t always enough. Many times you a combination of a Disposed event, a void Dispose(bool disposing) method for use by a deconstructor, a boolean flag to check if the object IsDisposed, and maybe a method to check if the object is disposed that can throw an exception. Some "best practices" often dictate that you should be using some of these additional things. You may be writing this logic over and over again for each class, or you might start with a basic IDisposable pattern and weeks later you decide to refactor it to add in something like the boolean flag for IsDisposed.
After facing these same issues for awhile, I decided to put together a simple Diposable base class with all of the recommended patterns for using Disposable. Of course, this can’t always be used since you might already have a base class. But many times a class will derive from IDisposable and nothing else. This is just screaming for a Disposable base class that encapsulates this logic! For classes that already have a base class, I also have a code snippet to include everything that’s in the base class.
Here are the features of the Disposable Base Class and Code Snippet:
- void Dispose() Method – This is just the standard Dispose method that is defined in the IDisposable interface.
- void Dispose(bool disposing) Method – This method is called from the Dispose() method passing in true. Its called from the deconstructor using false. This is the method that you should override in your parent class and check if disposing is true before disposing of managed code. The reason for this is that the deconstructor would have already disposed of the managed code, so you shouldn’t try to do it again. If the deconstrutor called this method, you should only dispose of unmanaged code.
- void CheckDisposed() Method – This method is marked protected and is used by the parent class to check if the object is disposed. It will throw an ObjectDisposedException if necessary.
- bool IsDisposed Property – A simple property to check whether or not this object has been disposed yet.
- Disposed Event – This event is fired when the object has been disposed.
To use the base class, you just override the Dispose(bool disposing) method. An example of this base class in use could look like this:
public class MyClass : Disposable { protected override void Dispose(bool disposing) { if (disposing) { // Dispose any managed code here } // Dispose any unmanaged code here base.Dispose(disposing); } }
Here is the base class:
using System; using System.ComponentModel; namespace Rigsby { /// <summary> /// Represents a basic disposable class. /// </summary> public abstract class Disposable : IDisposable { #region Private Properties private bool m_IsDisposed = false; #endregion Private Properties #region Public Properties /// <summary> /// Gets a value indicating whether this instance is disposed. /// </summary> /// <value> /// <c>true</c> if this instance is disposed; otherwise, <c>false</c>. /// </value> [Browsable(false)] public bool IsDisposed { get { return m_IsDisposed; } } #endregion Public Properties #region Constructors /// <summary> /// Initializes a new instance of the <see cref="Disposable"/> class. /// </summary> public Disposable() { } /// <summary> /// Releases unmanaged resources and performs other cleanup operations before the /// <see cref="Disposable"/> is reclaimed by garbage collection. /// </summary> ~Disposable() { Dispose(false); } #endregion Constructors #region IDisposable Members private event System.EventHandler m_Disposed; /// <summary> /// Occurs when this instance is disposed. /// </summary> public event System.EventHandler Disposed { add { m_Disposed += value; } remove { m_Disposed -= value; } } /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> public void Dispose() { if (!m_IsDisposed) { this.Dispose(true); GC.SuppressFinalize(this); } } /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { try { if (disposing) { EventHandler handler = m_Disposed; if (handler != null) { handler(this, EventArgs.Empty); handler = null; } } } finally { m_IsDisposed = true; } } #endregion IDisposable Members /// <summary> /// <para> /// Checks if the instance has been disposed of, and if it has, throws an <see cref="ObjectDisposedException"/>; otherwise, does nothing. /// </para> /// </summary> /// <exception cref="ObjectDisposedException"> /// The instance has been disposed of. /// </exception> /// <remarks> /// <para> /// Derived classes should call this method at the start of all methods and properties that should not be accessed after a call to <see cref="Dispose()"/>. /// </para> /// </remarks> protected void CheckDisposed() { if (m_IsDisposed) { string typeName = GetType().FullName; // TODO: You might want to move the message string into a resource file throw new ObjectDisposedException( typeName, String.Format(System.Globalization.CultureInfo.InvariantCulture, "Cannot access a disposed {0}.", typeName)); } } } }
Here is the code snippet version, or download it here. If you use the snippet, you will want to manually change your class to derive from the IDisposable interface, then add this snippet.
<?xml version="1.0" encoding="utf-8"?> <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>IDisposable</Title> <Shortcut> </Shortcut> <Description>Implements the IDisposable interface with additional best practices.</Description> <Author>Dan Rigsby</Author> </Header> <Snippet> <Code Language="csharp"><![CDATA[ #region IDisposable Members private bool m_IsDisposed = false; private event System.EventHandler m_Disposed; /// <summary> /// Gets a value indicating whether this instance is disposed. /// </summary> /// <value> /// <c>true</c> if this instance is disposed; otherwise, <c>false</c>. /// </value> [System.ComponentModel.Browsable(false)] public bool IsDisposed { get { return m_IsDisposed; } } /// <summary> /// Occurs when this instance is disposed. /// </summary> public event System.EventHandler Disposed { add { m_Disposed += value; } remove { m_Disposed -= value; } } /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> public void Dispose() { if (!m_IsDisposed) { this.Dispose(true); System.GC.SuppressFinalize(this); } } /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { try { if (disposing) { System.EventHandler handler = m_Disposed; if (handler != null) { handler(this, System.EventArgs.Empty); handler = null; } } } finally { m_IsDisposed = true; } } /// <summary> /// <para> /// Checks if the instance has been disposed of, and if it has, throws an <see cref="ObjectDisposedException"/>; otherwise, does nothing. /// </para> /// </summary> /// <exception cref="System.ObjectDisposedException"> /// The instance has been disposed of. /// </exception> /// <remarks> /// <para> /// Derived classes should call this method at the start of all methods and properties that should not be accessed after a call to <see cref="Dispose()"/>. /// </para> /// </remarks> protected void CheckDisposed() { if (m_IsDisposed) { string typeName = GetType().FullName; // TODO: You might want to move the message string into a resource file throw new System.ObjectDisposedException( typeName, String.Format(System.Globalization.CultureInfo.InvariantCulture, "Cannot access a disposed {0}.", typeName)); } } #endregion IDisposable Members]]></Code> </Snippet> </CodeSnippet> </CodeSnippets>

















April 9th, 2008 at 8:45 am
Hello Dan,
Thank you for the article.
If I may, I would like to introduce you to a Tool called Smarties 2008. Smarties 2008 supports a command called “Smart IDisposable” as part of Smart Inerfaces with four different Implementations. The best thing about Smart Interfaces are they can refactor themselves if the developer wants to change the implementation type.
The direct page to Smart Interfaces is Smart Interfaces.
I’m glad there are developers take this interface seriously because of the GC many developers are under impressions that there is no need to use IDisposable pattern. Having said that such developers would miss the “using” keyword in C# 2.0 since it requires the class to implement IDisposable now.
Thank you again.