Properly using and implementing the IDisposable pattern

IDisposable is a pattern in .NET that is used to implement deterministic cleanup of unmanaged resources. .NET has a garbage collector, but that is only used to manage memory, not resources like I/O (file handles, sockets, …). While in C++ destructors are called deterministically when an object goes out of scope, finalizers in C# get called by the garbage collector, but we can’t determine when that will happen (indeterministic deallocation). Don’t depend on the garbage collector for unmanaged resources!

Properly disposing resources

The IDisposable-interface has a single method void Dispose(). This method is used to clean up the disposable object and release the unmanaged resources it holds. To make sure that you always call it, even if an exception occurs in the code between creating the object and calling its Dispose-method, you should use the try-finally-construct, like this:

var x = new X(); // X is a class that implements IDisposable
try
{
  // do something with x
}
finally
{
  x.Dispose();
}

Because this pattern is so common, C# has the using-construct that does this more succinctly:

using (var x = new X())
{
  // do something with x
}

The advantage of this construct is that you can easily nest it without writing a lot of code:

using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
  using (var writer = new StreamWriter(stream, Encoding.UTF8))
  {
    foreach (string line in lines)
    {
      writer.WriteLine(line);
    }
  }
}

Or with less indentation and curly braces:

using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
  foreach (string line in lines)
  {
    writer.WriteLine(line);
  }
}

This is (more or less) equivalent to the following code:

var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
try
{
  var writer = new StreamWriter(stream, Encoding.UTF8);
  try
  {
    foreach (string line in lines)
    {
      writer.WriteLine(line);
    }
  }
  finally
  {
    writer.Dispose();
  }
}
finally
{
  stream.Dispose();
}

Properly implementing IDisposable in your own classes

Here’s the minimal proper implementation of IDisposable for a regular class that can be inherited (i.e. is not sealed):

public class MyDisposableType : IDisposable
{
  ~MyDisposableType()
  {
    // the finalizer also has to release unmanaged resources,
    // in case the developer forgot to dispose the object.
    Dispose(false);
  }
 
  public void Dispose()
  {
    Dispose(true);
 
    // this tells the garbage collector not to execute the finalizer
    GC.SuppressFinalize(this);
  }
 
  protected virtual void Dispose(bool disposing)
  {
    if (disposing)
    {
      // clean up managed resources:
      // dispose child objects that implement IDisposable
    }
 
    // clean up unmanaged resources
  }
}

In the classes that derive from such a disposable class, you don’t have to implement the entire pattern again: you can just override the Dispose(bool disposing)-method to add extra clean-up code. Just make sure you call the base-method (after the added code, in a finally-block):

public class MyDerivedDisposableType : MyDisposableType
{
  protected override void Dispose(bool disposing)
  {
    try
    {
      if (disposing)
      {
        // clean up managed resources:
        // dispose child objects that implement IDisposable
      }
 
      // clean up unmanaged resources
    }
    finally
    {
      // always call the base-method!
      base.Dispose(disposing);
    }
  }
}

If your class is sealed (so there can be no derived classes), you cannot have virtual methods. To properly implement the IDisposable-pattern, you could make the Dispose(bool disposing)-method private and not virtual:

public sealed class MySealedDisposableType : IDisposable
{
  ~MySealedDisposableType()
  {
    // the finalizer also has to release unmanaged resources,
    // in case the developer forgot to dispose the object.
    Dispose(false);
  }
 
  public void Dispose()
  {
    Dispose(true);
 
    // this tells the garbage collector not to execute the finalizer
    GC.SuppressFinalize(this);
  }
 
  private void Dispose(bool disposing)
  {
    if (disposing)
    {
      // clean up managed resources:
      // dispose child objects that implement IDisposable
    }
 
    // clean up unmanaged resources
  }
}