C#: System.Lazy<T> and the Singleton Design Pattern

Posted by James Michael Hare on Geeks with Blogs See other posts from Geeks with Blogs or by James Michael Hare
Published on Wed, 19 May 2010 16:41:12 GMT Indexed on 2010/05/19 23:50 UTC
Read the original article Hit count: 1127

Filed under:

So we've all coded a Singleton at one time or another.  It's a really simple pattern and can be a slightly more elegant alternative to global variables.  Make no mistake, Singletons can be abused and are often over-used -- but occasionally you find a Singleton is the most elegant solution.

For those of you not familiar with a Singleton, the basic Design Pattern is that a Singleton class is one where there is only ever one instance of the class created.  This means that constructors must be private to avoid users creating their own instances, and a static property (or method in languages without properties) is defined that returns a single static instance.

   1: public class Singleton
   2: {
   3:     // the single instance is defined in a static field
   4:     private static readonly Singleton _instance = new Singleton();
   5:  
   6:     // constructor private so users can't instantiate on their own
   7:     private Singleton()
   8:     {
   9:     }
  10:  
  11:     // read-only property that returns the static field
  12:     public static Singleton Instance
  13:     {
  14:         get 
  15:         {
  16:             return _instance; 
  17:         }
  18:     }
  19: }

This is the most basic singleton, notice the key features:

  • Static readonly field that contains the one and only instance.
  • Constructor is private so it can only be called by the class itself.
  • Static property that returns the single instance.

Looks like it satisfies, right?  There's just one (potential) problem.  C# gives you no guarantee of when the static field _instance will be created.  This is because the C# standard simply states that classes (which are marked in the IL as BeforeFieldInit) can have their static fields initialized any time before the field is accessed.  This means that they may be initialized on first use, they may be initialized at some other time before, you can't be sure when.

So what if you want to guarantee your instance is truly lazy.  That is, that it is only created on first call to Instance?  Well, there's a few ways to do this.  First we'll show the old ways, and then talk about how .Net 4.0's new System.Lazy<T> type can help make the lazy-Singleton cleaner.

Obviously, we could take on the lazy construction ourselves, but being that our Singleton may be accessed by many different threads, we'd need to lock it down.

   1: public class LazySingleton1
   2: {
   3:     // lock for thread-safety laziness
   4:     private static readonly object _mutex = new object();
   5:  
   6:     // static field to hold single instance
   7:     private static LazySingleton1 _instance = null;
   8:  
   9:     // property that does some locking and then creates on first call
  10:     public static LazySingleton1 Instance
  11:     {
  12:         get
  13:         {
  14:             if (_instance == null)
  15:             {
  16:                 lock (_mutex)
  17:                 {
  18:                     if (_instance == null)
  19:                     {
  20:                         _instance = new LazySingleton1();
  21:                     }
  22:                 }
  23:             }
  24:  
  25:             return _instance;
  26:         }
  27:     }
  28:  
  29:     private LazySingleton1()
  30:     {
  31:     }
  32: }

This is a standard double-check algorithm so that you don't lock if the instance has already been created.  However, because it's possible two threads can go through the first if at the same time the first time back in, you need to check again after the lock is acquired to avoid creating two instances.

Pretty straightforward, but ugly as all heck.  Well, you could also take advantage of the C# standard's BeforeFieldInit and define your class with a static constructor.  It need not have a body, just the presence of the static constructor will remove the BeforeFieldInit attribute on the class and guarantee that no fields are initialized until the first static field, property, or method is called.

 

   1: public class LazySingleton2
   2: {
   3:     // because of the static constructor, this won't get created until first use
   4:     private static readonly LazySingleton2 _instance = new LazySingleton2();
   5:  
   6:     // Returns the singleton instance using lazy-instantiation
   7:     public static LazySingleton2 Instance
   8:     {
   9:         get { return _instance; }
  10:     }
  11:  
  12:     // private to prevent direct instantiation
  13:     private LazySingleton2()
  14:     {
  15:     }
  16:  
  17:     // removes BeforeFieldInit on class so static fields not
  18:     // initialized before they are used
  19:     static LazySingleton2()
  20:     {
  21:     }
  22: }

Now, while this works perfectly, I hate it.  Why?  Because it's relying on a non-obvious trick of the IL to guarantee laziness.  Just looking at this code, you'd have no idea that it's doing what it's doing.  Worse yet, you may decide that the empty static constructor serves no purpose and delete it (which removes your lazy guarantee).  Worse-worse yet, they may alter the rules around BeforeFieldInit in the future which could change this.

So, what do I propose instead?  .Net 4.0 adds the System.Lazy type which guarantees thread-safe lazy-construction.  Using System.Lazy<T>, we get:

   1: public class LazySingleton3
   2: {
   3:     // static holder for instance, need to use lambda to construct since constructor private
   4:     private static readonly Lazy<LazySingleton3> _instance
   5:         = new Lazy<LazySingleton3>(() => new LazySingleton3());
   6:  
   7:     // private to prevent direct instantiation.
   8:     private LazySingleton3()
   9:     {
  10:     }
  11:  
  12:     // accessor for instance
  13:     public static LazySingleton3 Instance
  14:     {
  15:         get
  16:         {
  17:             return _instance.Value;
  18:         }
  19:     }
  20: }

Note, you need your lambda to call the private constructor as Lazy's default constructor can only call public constructors of the type passed in (which we can't have by definition of a Singleton).  But, because the lambda is defined inside our type, it has access to the private members so it's perfect.

Note how the Lazy<T> makes it obvious what you're doing (lazy construction), instead of relying on an IL generation side-effect.  This way, it's more maintainable.  Lazy<T> has many other uses as well, obviously, but I really love how elegant and readable it makes the lazy Singleton.

© Geeks with Blogs or respective owner