Singleton Pattern Implementation in C#: One Global Object Instance, One Entry Point

This post is going to explain how to implement the Singleton Pattern in .Net/C#. In most other programming languages/frameworks, global variables are allowed. In modern day programming this is extremely frowned upon, hence where this design pattern comes in handy: It provides a global object with only one point of reference. Once it is instantiated, all references to it are guaranteed to be to a single object instance which is available throughout the lifetime of the application.

So, where would this be useful? Keeping an application-wide cache of objects to avoid expensive calls to non-local resources. .Net makes this fairly simple. Here’s the basic UML diagram for a singleton object:

We create a static constructor (thus making sure only one object is created in the AppDomain) so the object can’t be created directly, a private backing store called instance of type of the singleton class, and a public accessor property (or method) that returns the private instance type. Your class must be declared as static (which implies sealed) otherwise subclasses can create new instances.

I cannot repeat this enough: Global variables are evil. Global objects are not. .Net uses the singleton pattern for the classes contained in the System.Runtime.Caching namespace, and I suspect this pattern is used on top of the Flyweight pattern (another post for later) for String Interning within the .Net framework..In my experience, the singleton pattern comes in most handy for creating a global class encompassing a variety of collections…really, just a global cache of resources that are expensive to recreate on a regular basis (e.g. an object gets garbage collected, then has to be recreated on a regular basis). Usually this data should be largely static in nature, but using the classes in the Caching namespace, you can easily create a singleton object that maintains itself via callbacks, expirations, etc., which is something I routinely do in my applications: Create a global Cache object, write the plumbing for it to tidy itself up, keep a global instance…et voila, all of the tedious/expensive code to expensive resources takes care of itself. I’ll provide a further example of the caching pattern I’ve developed in a future post.

Regardless, there are a couple of simple ways to implement this pattern in .Net. The first example is eager initialization, with a single lock check:and is thread safe:

   1: public sealed class Singleton
   2:  {
   3:      private static Singleton instance = null;
   4:      private static readonly object padlock = new object();
   6:      static Singleton()
   7:      {
   8:      }
  10:     public static Singleton Instance
  11:      {
  12:          get
  13:          {
  14:              lock (padlock)
  15:              {
  16:                  if (instance == null)
  17:                  {
  18:                      instance = new Singleton();
  19:                  }
  20:                  return instance;
  21:              }
  22:          }
  23:      }
  24:  }

Note: Always create a separate threadlock object, don’t lock on the class instance itself as that’s just begging for a deadlock/race condition. Locking a static private object will prevent deadlocks since it will not allow new threads to access the object until the lock is released: Calling code can pulse/queue as much as they want, but until the lock is released, they have to wait.

In .Net 4.0, it’s even easier to get thread safety and lazy instantiation via the Lazy<T> class:

   1: public sealed class Singleton
   2:  {
   3:      private static readonly Lazy<Singleton> lazy =
   4:          new Lazy<Singleton>(() => new Singleton());
   6:      public static Singleton Instance { get { return lazy.Value; } }
   8:     private Singleton()
   9:      {
  10:      }
  11:  }

Very few lines of code, and we get thread safety, lazy initialization, and type safety. What’s the difference? It depends on what the object needs to acquire, and how expensive those resources are to acquire. I would lean towards lazy instantiation, mainly because I believe resources should be acquired as needed. A caveat though: code needs to be written to maintain the singleton’s references and memory usage. This tends to be a pattern that is overused in place of globals, and can be just as detrimental.

Next post, a simple caching wrapper utilizing the singleton pattern.