Implementing IDisposable

In the IDisposable and using in C# post I showed how to handle an object that implements IDisposable. That’s the most common scenario, where a simple using will ensure that resources are properly and early released, but that only handles the case when the resource is created and disposed of in the same function. What if the resource is a member of a class?

I have created a simple logging class that writes an opening line whenever the log is opened.

public class LogWriter
{
    private StreamWriter m_Stream;
 
    public LogWriter(string logFile)
    {
        m_Stream = new StreamWriter(logFile, true);
        m_Stream.WriteLine("Starting logging at {0}", DateTime.Now);
    }
 
    public void WriteLine(string message)
    {
        m_Stream.WriteLine(message);
    }
}

The StreamWriter created in the constructor implements IDisposable so we should call it’s Dispose method. But from where? The answer is to let the LogWriter implement IDisposable

IDisposable implementation

The requirements on a correct IDisposableimplementation are:

  • Multiple calls to Dispose must be handled gracefully.
  • Child classes must have a chance to dispose their resources, including any unmanaged resources.
  • The finalizer should not be called if the object is already disposed.

To handle all these requirements there is a common pattern, which is implemented in the below example.

public class LogWriter : IDisposable
{
    private StreamWriter m_Stream;
 
    public LogWriter(string logFile)
    {
        m_Stream = new StreamWriter(logFile, true);
        m_Stream.WriteLine("Starting logging at {0}", DateTime.Now);
    }
 
    public void WriteLine(string message)
    {
        m_Stream.WriteLine(message);
    }
 
    #region IDisposable implementation
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    private bool m_Disposed = false;
 
    protected virtual void Dispose(bool disposing)
    {
        if (!m_Disposed)
        {
            if (disposing)
            {
                m_Stream.Dispose();
            }
 
            // Unmanaged resources are released here.
 
            m_Disposed = true;
        }
    }
 
    ~LogWriter()    
    {        
        Dispose(false);
    }
 
    #endregion
}

The Dispose() method defined by the IDisposable interface is a wrapper, around a protected worker method Dispose(bool) that does all the work. In the Dispose() method there is also a call to GC.SupressFinalize(this). This will enable the garbage collector to release the memory of the object directly when it is no longer in use. If we omit this call, the garbage collector will have to put the object on the finalizer que instead of releasing it. Once the finalizer has been run (by a background thread) the object is eligible for garbage collection, but it won’t be collected until the GC is run again. When the finalizer is suppressed, the GC is able to collect the object on the first run.

The worker method is also called from the finalizer ~LogWriter() to ensure that any unmanaged resources are correctly released even if Dispose() was not called.

The main work is done in the Dispose(bool) method. It will first check a flag to ensure that we are not disposing twice. The disposing flag is important, because if called from dispose we want to release any managed resources early. If called from the finalizer it would be an error to touch any managed references. We have no idea if they are still alive, or if the GC freed those objects before freeing this object. Any unmanaged resources should of course be released anyways.

Inherited classes

What if we inherit the LogWriter class? Thanks to all the plumbing code in the base class we only have to override Dispose(bool).

public class DetailedLogWriter : LogWriter
{
    public DetailedLogWriter(string logFile)
        : base(logFile)
    {
        WriteLine(string.Format("Logging from {0}", 
            Assembly.GetExecutingAssembly().FullName));
    }
 
    private bool m_Disposed = false;
 
    protected override void Dispose(bool disposing)
    {
        if (!m_Disposed)
        {
            WriteLine(string.Format("Logging ended on {0}", DateTime.Now));
            WriteLine(string.Empty);
            base.Dispose(disposing);
        }
 
        base.Dispose(disposing);
    }
}

More Reading

There are a couple of great articles on Code Project about IDisposable. IDisposable: What Your Mother Never Told You About Resource Deallocation describes in depth on why the IDisposable construct is needed. Implementing IDisposable and the Dispose Pattern Properly goes deeper into how to implement IDisposable correctly.

This post is part of the IDisposable series.<< IDisposable and using in C#Disposable Base Class >>

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.