IDisposable Pattern

When I started out with .NET, I wasn’t quite happy with the documentation provided for the IDisposable interface by Microsoft. The examples always depicted some class using an unmanaged resource that needed to be evicted from memory. To achieve this, said class implemented IDisposable, a finalizer and a Dispose(bool disposing) that was called from both the finalizer and the IDisposable.Dispose() method.

But it didn’t tell me that you don’t need the whole disposable pattern with a finalizer and Dispose(bool disposing) method unless your class actually owns an unmanaged handle directly. Or that adding a finalizer to a class means each instance of it is tracked in a finalization queue, which means more work for the garbage collector.

This article will introduce you to the disposable pattern the way I would have wished for when I switched to .NET!

Why Dispose?

.NET is a runtime environment based on garbage collection. That means instead of allocating memory, using it and then freeing it again, you can just allocate away and when your program has no more references to the allocated memory, .NET will free it for you automatically.

This is done by the garbage collector. It will run every now and then, check which objects your application is no longer referencing (so called “garbage”) and reclaim the resources used by those objects.

This works great for memory, but what if the object in question is a file? Open the file, write to it and then… just let it go. It will eventually be closed — but you don’t know when the garbage collector will come around to do it. So the file stays locked until this happens. Not good if you’re writing an image editor where the user might want to use the image file after he saved it.

By explicitly disposing objects, you can tell .NET that you want a resource freed right here and now.

IDisposable

The IDisposable interface is just an interface with a single method named Dispose(), nothing more. It has no special meaning for the .NET runtime and implementing it will not change your object’s behavior at all.

UML diagram of the IDisposable interface

All it’s good for is to provide a standardized way for you to tell an object to release its resources. The C# language even provides some built-in support for IDisposable. Instead of writing:

IDisposable disposableObject = createSomething();
try {
  DoSomethingWhichMightThrow();
}
finally {
  disposableObject.Dispose();
}

C# lets you write:

using(IDisposable disposableObject = createSomething()) {
  DoSomethingThatMightFail();
}

As stated before, this is a pure C# language feature that will be rewritten to something resembling the former code example when it is compiled to IL code.

Finalizers

Finalizers are special methods that get called when an object is collected by the garbage collector. They can be seen as an emergency path to release unmanaged resources if the user of an object forgot to call IDisposable.Dispose() on it.

Adding a finalizer to a class means that whenever you create an instance of said class, that instance will be added to a global finalization queue that tells the garbage collector not to reclaim the object’s memory until its finalizer has been executed. This of course means additional management overhead.

That’s why you often see this little trick in classes with a finalizer:

class MyClass : IDisposable {

  /// <summary>Finalizer that will be called by the GC</summary>
  ~MyClass() {
    ReleaseUnmanagedResources();
  }

  /// <summary>Immediately releases all resources owned by the object.</summary>
  public void Dispose() {
    ReleaseManagedResources();
    ReleaseUnmanagedResources();

    // We have released our resources already. Tell the GC that it
    // doesn't need to call the finalizer anymore.
    GC.SuppressFinalize(this);
  }

}

GC.SuppressFinalize() removes the instance from the finalization queue, so the garbage collector can now reclaim the object without waiting for its finalizer to be executed.

Notice

Do not access any other objects in your finalizer!

When the finalizer is called, you do not know if any other objects being referenced are still alive. Also do not call the Dispose() method on any other objects in your finalizer – they may be gone already.

Simplified Disposable Pattern

You can support the disposable pattern to two different degrees. This simplified variant is the one you should prefer as long as your class is not the direct owner of an unmanaged resource.

Use it whenever you need to call Close() on a FileStream, unregister from an event or when your class owns another object that implements IDisposable (which might even be an object that wraps an unmanaged resource itself and requires the full disposable pattern)

You can implement IDisposable in a very simple manner by only adding IDisposable to the list of interfaces for your class and writing the finalization code directly into the Dispose() body:

class MyClass : IDisposable {

  /// <summary>Immediately releases all resources owned by the object</summary>
  public void Dispose() {
    // Perform object finalization here
  }

}

Example

Let’s take an example from my favorite topic, game programming, and check out how IDisposable could be used in a real-world scenario that doesn’t have anything to do with unmanaged resources!

UML diagram showing a loading screen that registers to a progress event

Let’s see:

  • The Game class can load levels asynchronously
  • While it is loading, Game regularly triggers the LoadingProgressUpdated event to notify its subscribers about the achieved progress
  • The LoadingScreen class subscribes to the Game‘s LoadingProgressUpdated event

Looks like the perfect construction kit for a game with a loading screen!

Now what if the level has been loaded and the loading screen is no longer needed? Thanks to the gargabe collector we could just drop it, right?

Right. Except that the garbage collector will not reclaim the LoadingScreen because it’s still subscribed to the Game.LoadingProgressUpdated event (in other words, the Game class still has a reference to it).

And that, when the player finishes the level and we set up another loading screen for the next level being loaded, it will still be registered. In level 10, the Game class will already have 10 LoadingScreens subscribed to it. Oops.

That’s where we could use IDisposable: Let the LoadingScreen implement IDisposable and unsubscribe from the event when it’s disposed. Then take care to call LoadingScreen.Dispose after a level has finished loading and everything is fine.

Full Disposable Pattern

This is the IDisposable implementation you will see demonstrated in the MSDN docs and that a lot of developers have come to accept as the only way to add finalization code to a class. It is only required in the specific case where a class directly owns an unamaneged resource handle.

class MyClass : IDisposable {

  /// <summary>Finalizer that will be called by the GC.</summary>
  ~MyClass() {
    Dispose(false); // false == called by the GC
  }

  /// <summary>Immediately releases all resources owned by the object.</summary>
  public void Dispose() {
    Dispose(true); // true == called explicitly by user code

    // We have released our resources already. Tell the GC that it
    // doesn't need to call the finalizer anymore.
    GC.SuppressFinalize(this);
  }

  /// <summary>Immediately releases all resources owned by the object.</summary>
  /// <param name="calledExplicitly">
  ///   If true, the object is being disposed explicitly and can still access
  ///   other managed objects it is referencing. If false, other managed objects
  ///   maybe have been destroyed already and mustn't be touched.
  /// </param>
  protected virtual void Dispose(bool calledExplicitly) {
    if(calledExplicitly) {
      // Perform finalization of managed objects here
    }
    
    // Perform finalization of unmanaged objects here
  }

}

As you might have noticed, I took the liberty of renaming the disposing parameter you will find in the MSDN example to calledExplicitly. That’s because having a parameter named disposing in a method named Dispose() doesn’t exactly light a candle to me ;)

The important thing to note here is that managed resources will only be disposed if the Dispose(bool calledExplicitly) method is invoked by an explicit call through IDisposable.Dispose(). This is important because, as mentioned before, if the method is being executed through the finalizer, it must not access any other objects, not even to call Dispose() on them – they may have already been destroyed.

Example

Here’s an example demonstrating the use of the full disposable pattern with a finalizer and everything:

UML diagram showing a database class using unmanaged resources

What do we have here?

  • A DatabaseConnection class that communicates with some proprietary database engine through a “pipe”
  • Said “pipe” is an unmanaged resource that needs to be closed, so the DatabaseConnection class implements the full disposable pattern.
  • A DatabaseWriter class the owns a DatabaseConnection instance. It implements the lightweight disposable pattern.

Without the finalizer (DatabaseConnection.~DatabaseConnection()), if the programmer forgot to call Dispose() on his DatabaseConnection, the pipe would never be closed since the garbage collector doesn’t know what to do with the IntPtr.

But with the finalizer in place, the garbage collector will call it and be able to close the pipe even if the programmer forgot to do so explicitly.

The DatabaseWriter class doesn’t have a finalizer. It couldn’t do anything in it anyway – calling DatabaseConnection.Dispose() would be risky because the DatabaseConnection could already be destroyed at this point.

So DatabaseWriter uses the lightweight dispose pattern and disposes the DatabaseConnection only if it is explicitly called.