Click here to Skip to main content
16,021,810 members
Articles / Programming Languages / C#

Singleton Design Pattern in C#: Part 1

Rate me:
Please Sign up or sign in to vote.
3.33/5 (11 votes)
8 Jan 2018CPOL11 min read 45.8K   514   15   11
This article covers Singleton Pattern in the most simplistic and easy to understand. The article will also talk about Static classes and the differences between singleton design pattern and static classes.

Contents

Introduction

I always wanted to write about Singleton design pattern in C#. Though there already are many posts available on Singleton design pattern, I'll try to cover this topic in the most simplistic way and easy to understand. The article will also talk about Static classes and the differences between singleton design pattern and static classes. This is two article tutorial series to learn Singleton. Following is the link to next article.

Singleton Design Pattern - Part 2

The Pattern Itself

The Singleton design pattern is a creational type of design pattern. We have distinct categories of design patterns, out of which creational is the one which deals with instance creation and initialization. This pattern helps a programmer to write a program with more flexibility of creating objects subjective to various cases, the example of which are Singleton, Factory, Abstract factory etc. Covering design pattern types are out of the scope of this article, so let's focus on Singleton design pattern. A Singleton design pattern says or enables a developer to write code where only one instance of a class is created and the threads or other processes should refer to that single instance of the class. We at certain point in time might be in a situation where we need to write code where we only need one instance of a class and if some other class tries to create an object of that class, then the already instantiated object is shared to that class. One very common and suitable example is a log writer class. We might have a situation where we must maintain a single file for writing logs for requests coming to our .NET application from various clients like mobile client, web client or any windows application client. In this case there should be a class which takes this responsibility of writing the logs in a single file. Since requests come from multiple clients simultaneously, there should be a mechanism where only one request is logged at a time. Also, other requests should not be missed, and instead should be diligently logged, so that those requests when logged, do not override or conflict with the already logged requests. To achieve this, we can make a class singleton by following singleton pattern guidelines where a single thread-safe object is shared between all the requests which we'll discuss in detail in this article with practical examples.

Advantages of Singleton

Let's highlight the advantages of singleton class or pattern first before we jump into actual implementation. The first advantage that we can make out from the request logging example is that singleton takes care of concurrent access to shared resource, which means if we are sharing a resource with multiple clients simultaneously, then it should be well taken care of. In our case, our log file is the shared resource and singleton makes sure every client accesses it with no deadlock or conflict. The second advantage is that it only allows one instance of a class responsible for sharing the resource, which is shared across all the clients or applications in a controlled state.

Guidelines

Every pattern is based on certain guidelines which should be followed while implementing the pattern. These guidelines help us build a robust pattern and each guideline has its significance in the pattern that we'll discuss while creating singleton class. Stick to the following guidelines whenever you need to implement singleton design pattern in C#.

  1. Check that the implementation when done, creates only one instance of the class, and there should be only one point from where an instance is to be created.
  2. The singleton's class constructors should be private so that no class can directly instantiate the singleton class.
  3. There should be a static property/method that takes care of singleton class instantiation and that property should be shared across applications and is solely responsible for returning a singleton instance.
  4. The C# singleton class should be sealed so that it could not be inherited by any other class. This is useful when we dealing with nested class structure. We'll discuss this scenario as well later when we implement singleton.

Basic Singleton Implementation

A lot of theory covered, now let's practically implement the singleton pattern. We'll cover this step by step.

  1. Open Visual Studio and create a console application named Singleton (you can choose whatever name you like)

    Image 1

  2. Add a class named Singleton and add the following code to log a request message to it. For now, we are not actually logging into file, but displaying the message at console.

Singleton.cs

C#
using static System.Console;

namespace Singleton
{
  class Singleton
  {
    public void LogMessage(string message)
    {
      WriteLine("Message " + message);
    }
  }
}

Let's also add a public constructor in the class with a variable to hold the counter of number of objects created of this singleton class. We increment the instanceCounter variable whenever an instance of the Singleton class is created, so the best place to increment and print it is constructor.

C#
using static System.Console;

namespace Singleton
{
  class Singleton
  {
    static int instanceCounter = 0;
    public Singleton()
    {
      instanceCounter++;
      WriteLine("Instances created " + instanceCounter);
    }
    public void LogMessage(string message)
    {
      WriteLine("Message " + message);
    }
  }
}

Note that we are not using any singleton guideline here and first we'll try to invoke this method from our main method (for example, in Program.cs class). So, go to Program.cs class and write the following code for calling that LogMessage method of singleton class by creating an object of that class. We assume that two clients or two classes (Manager class and Employee class) are creating the objects of Singleton class to log their request message. Let's name those instances as "fromManager" and "fromEmployee".

Program.cs

C#
using static System.Console;
namespace Singleton
{
  class Program
  {
    static void Main(string[] args)
    {
      Singleton fromManager = new Singleton();
      fromManager.LogMessage("Request Message from Manager");

      Singleton fromEmployee = new Singleton();
      fromEmployee.LogMessage("Request Message from Employee");

      ReadLine();
    }
  }
}

When we run the application, we see the following output:

Image 2

We see here that we created two instances of our class named Singleton and got the method invoked by both the objects separately. When the first time fromManager instance was created the counter was incremented by 1 and the second time at the time of fromEmployee instance creation, it is incremented again by 1 so 2 in total. Note that we have not yet implemented singleton guidelines and our aim is to restrict this multiple object creation.

  1. If we again refer the guidelines, it says that all the constructors of the singleton class should be private and there should be a property or method which takes responsibility of providing the instance of that singleton class. So, let's try that. Convert the public constructor in the Singleton class a private as the following:
    C#
    private Singleton()
    {
      instanceCounter++;
      WriteLine("Instances created " + instanceCounter );
    }
    

    But when you go back to the Program.cs class where we were making the instance we see the error as follows which is a compile time error and appears as well when we compile the program at this point of time.

    Image 3

It says that the constructor could not be accessed and that's because we have made it private. So let's delegate those responsibilities of serving objects to a static property in the Singleton class. Add a new property in the Singleton class which makes use of a backing field to return the object.

Image 4

The following is the code:

C#
using static System.Console;

namespace Singleton
{
  class Singleton
  {
    static int instanceCounter = 0;
    private static Singleton singleInstance = null;
    private Singleton()
    {
      instanceCounter++;
      WriteLine("Instances created " + instanceCounter );
    }

    public static Singleton SingleInstance
    {
      get
      {
        if (singleInstance == null)
        {
          singleInstance = new Singleton();
        }
        return singleInstance;
      }
    }
    public void LogMessage(string message)
    {
      WriteLine("Message " + message);
    }
  }
}

If we go through the above code, we simply created a backing field named singleInstance and a public static property named SingleInstance. Whenever this property would be accessed, it will instantiate the backing field with a new Singleton instance and return it to the client, but not every time, and to ensure that we check that if the singleInstance is null then only it return the new instance and not every time the property is accessed. For all other times, it should return the same instance as was initially created. Since the constructor of this class is now private, it could only be accessed from within the class members and not from outside the class. Now go to the program.cs class and access this property for getting the instance as we now cannot directly create a Singleton instance due to private constructor.

Image 5

The following is the code:

C#
using static System.Console;
namespace Singleton
{
  class Program
  {
    static void Main(string[] args)
    {
      Singleton fromManager = Singleton.SingleInstance;
      fromManager.LogMessage("Request Message from Manager");

      Singleton fromEmployee = Singleton.SingleInstance;
      fromEmployee.LogMessage("Request Message from Employee");

      ReadLine();
    }
  }
}

Now when we run the application we get following output.

Image 6

It clearly states that only one instance of the Singleton class was created, but our methods were called distinctly for both the callers. This is because at the first time the instance was created, but the second time when the property was accessed by fromEmployee the already created object was returned.

So, no doubt that we have implemented the single design pattern, and changed the object creation strategy of this Singleton class, but this is a very basic implementation of Singleton design pattern and it still do not take care of deadlock situations and accessing class in multithreaded environment. Let's see how we can make this class thread safe as well. Make the singleton class sealed before we proceed. We'll discuss why we made the class sealed later.

Thread-Safe Singleton Implementation

Problem

Our basic level implementation only would work in a single threaded system because our instance creation is lazily initialized which means we only create the instance when the SingleInstance property is invoked. Suppose there is a situation where two threads try to access the property at a same time, in that case it could be a situation that both the threads hit the null check at the same time and get access to new instance creation because they find the instance variable still null. Let's test this scenario in our current Singleton implementation.

Go to the Program.cs class and create two methods named LogEmployeeRequest and LogManagersRequest and move the logging code for both the instances to these methods as shown below.

Image 7

Now, let's try to invoke these methods parallelly using Parallel.Invoke method as shown below. This method can invoke multiple methods parallelly and so we would get into a situation where both methods claim Singleton instance at a same time. Parallel is the class under System.Threading.Tasks namespace.

Image 8

The following is the code:

C#
using System.Threading.Tasks;
using static System.Console;
namespace Singleton
{
  class Program
  {
    static void Main(string[] args)
    {
      Parallel.Invoke(() => LogManagerRequest(), () => LogEmployeeRequest());
      ReadLine();
    }

    private static void LogManagerRequest()
    {
      Singleton fromManager = Singleton.SingleInstance;
      fromManager.LogMessage("Request Message from Manager");
    }
    private static void LogEmployeeRequest()
    {
      Singleton fromEmployee = Singleton.SingleInstance;
      fromEmployee.LogMessage("Request Message from Employee");
    }
  }
}

Now when we run the application we get the following output:

Image 9

The above output clearly states that we ended up creating two instances of Singleton class as our constructor was called twice. That's because both the methods executed at the same time. Now to overcome this situation we can further enhance our Singleton class.

Solution

One of the way to overcome this situation is to use locks. We can use lock over an object if any thread tries to access the instance and in that case, the other thread waits until the lock is released. Let's implement this. Update your Singleton class in the following manner.

Image 10

The following is the code:

C#
using static System.Console;

namespace Singleton
{
  sealed class Singleton
  {
    static int instanceCounter = 0;
    private static Singleton singleInstance = null;
    private static readonly object lockObject = new object();
    private Singleton()
    {
      instanceCounter++;
      WriteLine("Instances created " + instanceCounter );
    }

    public static Singleton SingleInstance
    {
      get
      {
        lock (lockObject)
        {
          if (singleInstance == null)
          {
            singleInstance = new Singleton();
          }

        }
        return singleInstance;
      }
    }
    public void LogMessage(string message)
    {
      WriteLine("Message " + message);
    }
  }
}

In the above-mentioned source code we created a private static readonly object type variable and initialized it. Then in the SingleInstance property we wrapped the code of instance creation under the lock, so that one thread can enter the code at a time and other thread waits until first thread finishes its execution. Now let's run the application and check the output. Compile and Run.

Image 11

So, now only one instance of Singleton class is created, that means our lock works fine. We still have a problem with the current implementation. The problem is that our lock object code will be called everytime the property of SingleInstance is accessed which may incur a huge performance cost on application as locks are quite expensive when we want good performance in our application. So, we can restrict this every time lock code access by wrapping is under the condition that it could only be accessed if singleInstance backing field is null. Therefore, our code for property be like as shown below:

C#
public static Singleton SingleInstance
    {
      get
      {
        if (singleInstance == null)
        {
          lock (lockObject)
          {
            if (singleInstance == null)
            {
              singleInstance = new Singleton();
            }

          }
        }
        return singleInstance;
      }
    }

Now when we run the application, the lock code would not be executed every time but only for the first time when it is accessed because at the second time it will not find the singleInstance field as null. Complete class code is as following.

C#
using static System.Console;

namespace Singleton
{
  sealed class Singleton
  {
    static int instanceCounter = 0;
    private static Singleton singleInstance = null;
    private static readonly object lockObject = new object();
    private Singleton()
    {
      instanceCounter++;
      WriteLine("Instances created " + instanceCounter );
    }

    public static Singleton SingleInstance
    {
      get
      {
        if (singleInstance == null)
        {
          lock (lockObject)
          {
            if (singleInstance == null)
            {
              singleInstance = new Singleton();
            }

          }
        }
        return singleInstance;
      }
    }
    public void LogMessage(string message)
    {
      WriteLine("Message " + message);
    }
  }
}

We call this null instance check locking as "double check locking", which is often asked in the interviews. In the next article we'll see ho to get rid of this double check locking and still keep our singleton functionality intact and thread safe.

Conclusion

In this article, we discussed what is Singleton design pattern, when is it needed and what problems does it solve. We also discussed how to create a basic singleton class step by step and how to enhance that class to be thread safe with the help of locking and performance effective with the help of double check locking. For the sake of not making the article too long, I have divided the learning Singleton topic in two parts. Please refer next part of this article where we discuss Lazy initialization, Eager initialization, creating singleton without double check lock and why to make singleton class a sealed class and what are the differences between singleton and static class. Next Article>>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect https://codeteddy.com/
India India
Akhil Mittal is two times Microsoft MVP (Most Valuable Professional) firstly awarded in 2016 and continued in 2017 in Visual Studio and Technologies category, C# Corner MVP since 2013, Code Project MVP since 2014, a blogger, author and likes to write/read technical articles, blogs, and books. Akhil is a technical architect and loves to work on complex business problems and cutting-edge technologies. He has an experience of around 15 years in developing, designing, and architecting enterprises level applications primarily in Microsoft Technologies. He has diverse experience in working on cutting-edge technologies that include Microsoft Stack, AI, Machine Learning, and Cloud computing. Akhil is an MCP (Microsoft Certified Professional) in Web Applications and Dot Net Framework.
Visit Akhil Mittal’s personal blog CodeTeddy (CodeTeddy ) for some good and informative articles. Following are some tech certifications that Akhil cleared,
• AZ-304: Microsoft Azure Architect Design.
• AZ-303: Microsoft Azure Architect Technologies.
• AZ-900: Microsoft Azure Fundamentals.
• Microsoft MCTS (70-528) Certified Programmer.
• Microsoft MCTS (70-536) Certified Programmer.
• Microsoft MCTS (70-515) Certified Programmer.

LinkedIn: https://www.linkedin.com/in/akhilmittal/
This is a Collaborative Group

779 members

Comments and Discussions

 
GeneralMy vote of 4 Pin
Lance Ford22-Jan-24 3:20
Lance Ford22-Jan-24 3:20 
Informative and easy to follow - thank you!
QuestionThe advantages of using the Singleton Pattern Pin
John Brett9-Jan-18 21:10
John Brett9-Jan-18 21:10 
QuestionLazy version now for anyone that wants it Pin
Sacha Barber8-Jan-18 21:53
Sacha Barber8-Jan-18 21:53 
AnswerRe: Lazy version now for anyone that wants it Pin
Akhil Mittal8-Jan-18 23:02
professionalAkhil Mittal8-Jan-18 23:02 
PraiseMy vote of 5 Pin
Vikas Sharma8-Jan-18 16:40
professionalVikas Sharma8-Jan-18 16:40 
GeneralRe: My vote of 5 Pin
Akhil Mittal8-Jan-18 17:16
professionalAkhil Mittal8-Jan-18 17:16 
GeneralYou'll never say it better than The Master Pin
PIEBALDconsult8-Jan-18 13:14
mvePIEBALDconsult8-Jan-18 13:14 
GeneralRe: You'll never say it better than The Master Pin
Akhil Mittal8-Jan-18 15:25
professionalAkhil Mittal8-Jan-18 15:25 
QuestionGetSingleInstance and better implementation. Pin
Paulo Zemek8-Jan-18 10:35
Paulo Zemek8-Jan-18 10:35 
AnswerRe: GetSingleInstance and better implementation. Pin
Akhil Mittal8-Jan-18 15:22
professionalAkhil Mittal8-Jan-18 15:22 
AnswerRe: GetSingleInstance and better implementation. Pin
Akhil Mittal8-Jan-18 17:19
professionalAkhil Mittal8-Jan-18 17:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.