Creating a Singleton (Instance) Class in C#

In application development there are various situations in which it makes sense to code a class in a manner that it can be created (instantiated) once and used throughout the lifetime of the application. Generally this type of class is called a Singleton object.

When creating and object, CPU cycles are used up during the:

  • Creation of the Object
  • Initialization of the Object
  • Loading of the Object, including seed data from the dB etc.

    If you have a class that is used throughout the application, but that does not need different instances of it, the Singleton Pattern is probably what you need.  Code Example:
using System;
public class Singleton
{
   private static Singleton instance;
   private Singleton() {}
   public static Singleton Instance
   {
      get
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

Benefits of using a Singleton Pattern:

  • Because the class instance is created inside the Instance property, the instantiation is not executed until the first object asks for an instance of the class. This approach is referred to as lazy instantiation. Lazy instantiation avoids creating Singletons when the application starts and only get created when they are actually needed.
  • While the private static instance variable is null, a new Instance of the Singleton class will be created. This is a good opportunity to “load” any supporting sub classes that are needed by the Singleton Instance.
  • A Singleton can be used throughout the application as soon as it is Instantiated. It will be the only instance of that class no matter where you are calling it from.
  • Singletons are very useful for State objects or Global Structure objects such as a “Session” object that keeps track of session information.

The class above will work on single threaded applications just fine, but if you application uses background threads to do work, you will need to implement a lock.

The code below will ensure that only one thread is allowed to go past the lock(syncRoot) line of code. Once the first thread has Instantiated the singleton, the second and all subsequent threads will return the one Instance created by the very first thread that reached the lock(syncRoot) line of code. Here it is:

using System;
public sealed class Singleton
{
  private static Singleton instance;
  private static volatile object syncRoot = new Object();
  private Singleton() { }

  public static Singleton Instance
  {
    get
    {
      // 4- all threads that did not reach lock will fail this check
      if (instance == null)
      {
        // 1- all threads wait here except for the first one that gets here
        lock (syncRoot)
        {
          // 3- all threads waiting at the lock will fail this check
          if (instance == null)
            // 2- only the first thread will reach here
            instance = new Singleton();
        }
      }
      // 5- all threads will eventually get here
      return instance;
      // The instance above has been created by the
      // first thread to reach the lock
      // all other threads, weather they reached
      // the lock or not, will return the
      // Instance created  by the first thread.
    }
  }
  public void DoSomeWorkPlease()
  {
    /// Do some work here
  }
}

public class MainProg
{
  public void Main()
  {
    Singleton.Instance.DoSomeWorkPlease();
  }
}

We declare our class as sealed to prevent anyone else from inheriting from it.

The code above is thread safe. The use of the volatile keyword ensures that assignment of the Instance variable completes before the Instance variable can be accessed by other threads. You can read a very detailed explanation of the volatile keyword here on a post by Igor Ostrovsky.

We lock onto the the syncRoot Object variable instead of locking on the Singleton type itself in order to avoid deadlocks. This internal lock allows us to control the accessing threads. If we were to lock onto the Singleton type, as in lock(this), we would not be able to control the accessing threads. Please see comments in code above.

Lastly, notice that we are checking for if (instance == null) twice. This is called “double check locking” and it solves thread concurrency problems because it avoids an exclusive lock on every call made to the Instance variable and will prevent from blocking more threads than we need.

We have added a method to the Singleton DoSomeWorkPlease(). Finally we show how to use the singleton in some very simple code.

Examples of Singleton classes that we now use in my current company are Session, Email Integration (com component wrapper) and Audit (for database field audit by whom etc.).

Have fun and let me know if you have any questions. Feel free to comment.

Computer

1 Comment


  1. This was a really helpful article and nicely put. Thanks.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *