November 2016

Volume 31 Number 11

[.NET Framework]

Hidden Disposables

By Artak Mkrtchyan | November 2016

Disposable types are great, as they let you free up resources in a deterministic way. However, there are situations where developers work with disposable types without even realizing it. The use of creational design patterns is an example of a situation where usage of a disposable type might not be obvious, which can lead to an object not getting disposed. This article will show ways to handle the problem. I’ll start by reviewing some of the creational design patterns.

Creational Design Patterns

A great benefit of the creational design patterns is that they abstract away from the actual implementations and “talk” in the interface language. They deal with object creation mechanisms to create objects that are suitable to the solution. In comparison with basic object creation, creational design patterns improve several aspects of the object creation process. Here are two well-known benefits of creational design patterns:

  • Abstraction: They abstract the object type being created, so the caller doesn’t know what the actual object being returned is—they’re aware of only the interface.
  • Creation internals: They encapsulate the knowledge about the specific type instance creation.

Next, I’ll give a brief overview of two well-known creational design patterns.

The Factory Method Design PatternThe Factory Method design pattern is one of my favorites and I use it a lot in my day-to-day work. This pattern uses factory methods to deal with the problem of creating objects without specifying the exact class of the object that’s created. Rather than calling a class constructor directly, you call a factory method to create the object. The factory method returns an abstraction (interface or a base class), which child classes implement. Figure 1 shows the Unified Modeling Language (UML) diagram for this pattern.

In Figure 1, the ConcreteProduct is a specific type of the IProduct abstraction/interface. Similarly, the ConcreteCreator is a specific implementation of the ICreator interface.

Factory Method Design Pattern
Figure 1 Factory Method Design Pattern

The client of this pattern uses an ICreator instance, and will be calling its Create method to get a new instance of IProduct, without knowing which actual product has been returned.

The Abstract Factory Design Pattern The goal of the Abstract Factory design pattern is to provide an interface for creating families of related or dependent objects without specifying concrete implementations.

This shelters the client code from the hassle of object creation by having the client ask the factory object to create an object of the desired abstract type and to return an abstract pointer to the object back to the client. In particular, this means the client code has no knowledge about the concrete type. It deals only with an abstract type.

Adding support for new concrete types is handled by creating new factory types and modifying the client code to use a different factory type as needed. In most cases, this is a one-line code change. This obviously simplifies handling changes, as the client code doesn’t need to change to accommodate the new factory type. Figure 2 shows the UML diagram for the Abstract Factory design pattern.

Abstract Factory Design Pattern
Figure 2 Abstract Factory Design Pattern

From a client perspective, the usage of the Abstract Factory is represented with the following piece of code:

IAbstractFactory factory = new ConcreteFactory1();
IProductA product = factory.CreateProductA();

The client is free to modify the actual factory implementation to control the type of product created behind the scenes and that will have absolutely no impact on the code.

This code is just a sample; in properly structured code, the factory instantiation itself would probably be abstracted away—with a factory method pattern as an example.

The Problem

In both of the design pattern examples, there was a factory involved. A factory is the actual method/procedure, which returns a constructed type reference through an abstraction in response to the client’s call.

Technically, you can use a factory to create an object, wherever an abstraction exists, as shown in Figure 3.

Example of Simple Abstraction and Its Usage
Figure 3 Example of Simple Abstraction and Its Usage

The factory handles the choice between different available implementations, based on the factors involved.

According to the Dependency Inversion principle:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend on details. Details should depend on abstractions.

This, technically speaking, means that on every level of a dependency chain, the dependency should be replaced by an abstraction. In addition, the creation of these abstractions can—and in many cases should be—handled through factories.

All this emphasizes how import­ant factories are in day-to-day coding. However, they’re actually hiding the problem: disposable types. Before getting into those details, I’ll first talk about the IDisposable interface and the Dispose Design pattern.

Dispose Design Pattern

All programs acquire resources such as memory, file handles and database connections during their execution. Developers have to be careful when using such resources because the resources must be released after they’ve been acquired and used.

The Common Language Runtime (CLR) provides support for automatic memory management through the garbage collector (GC). You don’t have to clean up Managed Memory explicitly because the GC will do that automatically. Unfortunately, there are other types of resources (referred to as Unmanaged resources) that still need to be explicitly released. The GC isn’t designed to handle these types of resources, so it’s the developer’s responsibility to release those.

Still, the CLR helps developers deal with unmanaged resources. The System.Object type defines a public virtual method, called Finalize, which is called by the GC before the object’s memory is reclaimed. The Finalize method usually is referred to as finalizer. You can override the method to clean up additional unmanaged resources used by the object.

This mechanism, however, has some drawbacks due to certain aspects of the GC execution.

The finalizer is called when the GC detects that an object is eligible for collection. This happens at an undetermined period after the object isn’t needed anymore.

When the GC needs to call the finalizer, it has to postpone the actual memory collection to the next round of garbage collection. This postpones the object’s memory collection even longer. That’s where the System.IDisposable interface comes in. The Microsoft .NET Framework provides the IDisposable interface that you need to implement to provide the developer a mechanism for manually releasing unmanaged resources. Types that implement this interface are called disposable types. The IDisposable interface defines just one parameter-less method, called Dispose. Dispose should be called to immediately release any unmanaged resources it references as soon as the object isn’t needed.

You might ask, “Why should I call Dispose myself when I know that GC will eventually handle it for me?” The answer requires a separate article, which also touches on aspects of the GC’s execution impact on performance. This is beyond the scope of this article, so I’ll move on.

There are certain rules to follow when deciding whether a type should be disposable. The rule of thumb is this: If an object of a given type is going to reference an unmanaged resource or other disposable objects, then it should also be disposable.

The Dispose pattern defines a specific implementation for the IDisposable interface. It requires two Dispose methods to be implemented: one public without parameters (defined by the IDisposable interface) and the other one a protected virtual with a single Boolean parameter. Obviously, if the type is going to be sealed, the protected virtual should be replaced by private.

Figure 4 Implementation of the Dispose Design Pattern

public class DisposableType : IDisposable {
  ~DisposableType() {
    this.Dispose(false);
  }
  public void Dispose() {
    this.Dispose(true);
    GC.SuppressFinalize(this);
  }
  protected virtual void Dispose(bool disposing) {
    if (disposing) {
      // Dispose of all the managed resources here
    }
    // Dispose of all the unmanaged resources here
  }
}

The Boolean parameter indicates the way in which the dispose method is being called. The public method calls the protected one with a parameter value “true.” Similarly, the overloads of the Dispose(bool) method in the class hierarchy should call base.Dispose(true).

The Dispose pattern implementation also requires the Finalize method to be overloaded. This is done to cover scenarios where a developer forgets to call the Dispose method after the object isn’t needed anymore. Because the finalizer is being called by the GC, the referenced managed resources might already (or will) be cleaned up, so you should handle the release of unmanaged resources only when the Dispose(bool) method is called from the finalizer.

Switching back to the main topic, the problem comes into play when you deal with disposable objects when used with creational design patterns.

Imagine a scenario where one of the concrete types implementing the abstraction also implements the IDisposable interface. Let’s assume it’s the ConcreteImplementation2 in my example, as shown in Figure 5.

Abstraction with an IDisposable Implementation
Figure 5 Abstraction with an IDisposable Implementation

Note that the IAbstraction interface itself does not inherit from the IDisposable.

Now look at the client code, where the abstraction is going to be used. As the IAbstraction interface hasn’t changed, the client won’t even care about any potential changes behind the scenes. Naturally, the client won’t guess that he’s been given an object, of which he’s now responsible to dispose. The reality is that an IDisposable instance isn’t really expected there and in many cases, those objects never get disposed explicitly by the client code.

The hope is that the actual implementation of the Concreate­Implementation2 implements the Dispose Design Pattern, which isn’t always the case.

It’s now obvious that the simplest mechanism to handle a case where the returned IAbstraction instance also implements IDisposable interface would be to introduce an explicit check in the client code, as shown here:

IAbstraction abstraction = factory.Create();
try {
  // Operations with abstraction go here
}
finally {
  if (abstraction is IDisposable)
    (abstraction as IDisposable).Dispose();
}

This, however, soon becomes a tedious procedure.

Unfortunately, a using block can’t be used with IAbstraciton, as it doesn’t extend IDisposable explicitly. So I came up with a helper class, which wraps the logic in the finally block and lets you use the using block, as well. Figure 6 shows the full code of the class and also provides a sample usage.

Figure 6 PotentialDisposable Type and Its Usage

public sealed class PotentialDisposable<T> : IDisposable where T : class {
  private readonly T instance;
  public T Instance { get { return this.instance; } }
  public PotentialDisposable(T instance) {
    if (instance == null) {
      throw new ArgumentNullException("instance");
    }
    this.instance = instance;
  }
  public void Dispose() {
    IDisposable disposableInstance = this.Instance as IDisposable;
    if (disposableInstance != null) {
      disposableInstance.Dispose();
    }
  }
}
The client code:
IAbstraction abstraction = factory.Create();
using (PotentialDisposable<IAbstraction> wrappedInstance =
  new PotentialDisposable<IAbstraction>(abstraction)) {
    // Operations with abstraction wrapedInstance.Instance go here
}

As you can see in the “The client code” part of Figure 6, using the PotentialDisposable<T> class reduced the client code to just a couple of lines with a using block.

You could argue that you could just update the IAbstraction interface and make it IDisposable. This may be the preferred solution in some situations, but not others.

In a situation where you own the IAbstraction interface and it makes sense for IAbstraction to extend IDisposable, you should do that. Actually, a good example of this would be the System.IO.Stream abstract class. The class actually implements the IDisposable interface, but it has no actual logic defined. The reason is that the writers of the class knew that most of the child classes will have some type of disposable members.

Another situation: When you do own the IAbstraction interface, but it doesn’t make sense for it to extend IDisposable, as most of the implementations of it are not disposable. Think about an ICustomCollection interface as an example. You have several in-memory implementations and suddenly you need to add some database-backed implementation, which will be the only disposable implementation.

The final situation would be when you don’t own IAbstraction interface—so you don’t have control over it. Consider an example of ICollection, which is backed by a database.

Wrapping Up

Whether or not the abstraction you get is through a factory method, it’s important to keep disposables in mind when writing your client code. Using this simple helper class is one way to ensure your code is being as efficient as possible when dealing with disposable objects.


Artak Mkrtchyan is a senior software engineer living in Redmond, Wash. He loves coding as much as he loves fishing.

Thanks to the following Microsoft technical expert for reviewing this article: Paul Brambilla
Paul Brambilla is a senior software developer at Microsoft specializing in cloud services and foundational infrastructure.


Discuss this article in the MSDN Magazine forum