Singleton Generics [updated]

The Singleton pattern is probably the most famous pattern of all. Usually it is implemented as a behaviour of a specific class. But why not let the developer decide how to manage instance lifetimes? The new .NET 2.0 Generics feature gives us just the tools for creating these object lifetime classes.

public static class StaticInstance<T>
    where T : new()
{
    private static T _instance;
    private static object _lock = new object();

    public static T Current
    {
        get
        {
            if (_instance == null)
            {
               lock (_lock)
               {
                   if (_instance == null)
                   {
                       _instance = new T();
                   }
               }
            }

            return _instance;
        }
    }
}

This code manages one instance of Type T in a (AppDomain) static variable, your typical Singleton implementation. Any class can be used as a Singleton now, just call StaticInstance<MyClass>.Current to access the instance of your type ‘MyClass’. Beware though that being a Singleton instance has concurrency issues in that multiple threads could access that one instance of your class at the same time.

In an ASP.NET context you often have the need to have "static" information available but private to the current request. Well, simply write another instance manager class such as this one:

public static class HttpContextInstance<T>
     where T : new()
{
     private static string _typeName = typeof(T).FullName;

     public static T Current
     {
          get
          {
              Debug.Assert(HttpContext.Current != null);

              T instance = (T)HttpContext.Current.Items[_typeName];

              if (instance == null)
              {
                  instance = new T();
                  HttpContext.Current.Items[_typeName] = instance;
              }

              return instance;
          }
    }

    public static void Dispose()
    {
        IDisposable instance = HttpContext.Current.Items[_typeName] as IDisposable;

        if (instance != null)
        {
            instance.Dispose();
        }

        HttpContext.Current.Items[_typeName] = null;
    }
}

The instance is stored in the Items collection of the HttpContext, thus making the instance private to just the current web request. I’ve also included a Dispose method to dispose of the instance’s resources when the request is done (global.asax) and clear the slot in the HttpContext items collection. You could think of other implementations for storing instances in the Thread Local Storage, the logical CallContext or any other place that might be convienient to you.

Have fun,
Marc Jacobi

 



[UPDATE 14-feb-06]

 

I like to point out some of the problems that you may encounter using this approach. The following issues should be taken into account:

  1. A Type specified for T must be able to cope with the concurrency consequences of the instance class implementation. For the StaticInstance example this means that it should syncronize access to its member variables.
  2. The Type (T) must have a public default constructor and your team could use that default constructor to create their own instances. For some types this is not a real big issue for others it can introduce hard-to-track-down bugs. If your Type (T) is not designed to be instantiated more than once implement your own Current property and remove your (default) constructor(s).
  3. All team members should "know" what Type (T) is accessed by which instance class. If one member uses StaticInstance<MyClass>.Current and another uses HttpContextInstance<MyClass>.Current you’ll have 2 instances living two different lifetimes. This is a weakness that can be overcome and we will discuss next.

Because C# (generics) does not support the typedef keyword (C++: allows defining a new type using other types declaratively) the only way to simplify and hardwire a generics type is to derive from it. So if you use the following code template for instance class implementations you can fix issue 3 by deriving a new type.

public class StaticInstance<T>
    where T : new()
{
    private StaticInstance()
    {}

    public static T Current
    {
        get
        {
            // [your implementation here]
        }
    }
}

Now, say you use a static instance of MyClass in your application you can derive a new type to hardwire the T parameter. This also gives you one point of definition for the MyClass-singleton and makes it easy to transparently change the instance class backing up the singleton.

public class MyClassSingleton : StaticInstance<MyClass>
{}

I hope this update gives you a better overview of the consequenses of using this approach.
Keep the questions and suggestions coming.

Greetings,
Marc Jacobi

  1. One thought on “Singleton Generics [updated]

    the parameter type of the generic needs public default constructor, so the type you’re using as a parameter is not singleton object itself. don’t you think there maybe problems, when some other member of your team will use this parameter type instead of the using it singletoned with this generic?

Comments are closed.