Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

An Absolute Beginner's Tutorial on Understanding and Implementing Singleton Pattern in C#

5.00/5 (17 votes)
20 Jan 2016CPOL5 min read 19.3K  
This article is yet another explanation and implementation of the singleton pattern.

Introduction

This article is yet another explanation and implementation of singleton pattern. We will look at what singleton pattern is and how to implement it in C#. This is no way the best and recommended way of implementing singleton pattern in C#. The main idea for this article is just to present the concept of singleton pattern to the reader.

Background

Whenever we have a scenario in our application where:

  • A single instance of a class is required in the application and the class itself is able to enforce the single instance on itself. The rest of the system need not have to worry about managing the single instance.
  • This single instance class should be accessible by the complete system or say by most part of the system.
  • This single instance subsystem should not be created and initialized unless it is required (lazy initialization).

Now let us see how we can have a class that will let the callers create only one single instance of it. To do that, the first thing we should ask ourselves is how instance of the classes are created. The answer to this question is by calling new for the class which in turn will call the constructor of the class. So if we want the applications not to be able to create by number of instances, we should first restrict access to the constructor, i.e., make the constructor private.

Now if we are making the constructor private, the next question we have is how will we be creating the instance of this class. Since the private constructor can still be called from the class itself, we can create an instance of this class inside the class itself. So to do this, we need to create a static method (static method will not need callers to have an instance to be called) inside the class, i.e., GetInstance which will create an object of this class and return it to the applications.

Using the Code

Let us now look at the class that is implementing the instance creation using the above discussed method and returning the instance to the caller.

C#
public sealed class Singleton
{
	// A private constructor to restrict the object creation from outside
	private Singleton()
	{

	}

	// A private static instance of the same class
	private static Singleton instance = null;

	public static Singleton GetInstance()
	{
		// create the instance only if the instance is null
		if (instance == null)
		{
			instance = new Singleton();
		}

		// Otherwise return the already existing instance
		return instance;
	}
}

Now, the above class will let the user create only one instance of this class, i.e., singleton in the simplest of forms.

Hello Multi-Threading

There is a problem with this class. It is not thread safe. So to make it thread safe, we need to make sure that the instantiation code can only be accessed by only a single thread at any given time. So let's do that and introduce a lock in our class to guard the GetInstance calls.

C#
public sealed class Singleton
{
	// A private constructor to restrict the object creation from outside
	private Singleton()
	{

	}

	// A private static instance of the same class
	private static Singleton instance = null;
	private static readonly object _lock = new object();

	public static Singleton GetInstance()
	{
		lock (_lock)
		{
			// create the instance only if the instance is null
			if (instance == null)
			{
				instance = new Singleton();
			}

			// Otherwise return the already existing instance
			return instance;
		}
	}
}

Now the instance retrieval code can only be accessed by one single thread at any given time. But this incorporates a performance problem. Our idea was to not let multiple threads be able to create multiple instances so we needed to guard the instance creation part in lock. What we have done instead is that we have guarded the complete method with lock. Which would mean that the lock will be acquired even when the instance has been created and it just needs to be returned. So to circumvent this problem, we need to guard only the instance creation part under lock and not the instance return part.

C#
public sealed class Singleton
{
	// A private constructor to restrict the object creation from outside
	private Singleton()
	{

	}

	// A private static instance of the same class
	private static Singleton instance = null;
	private static readonly object _lock = new object();

	public static Singleton GetInstance()
	{
		if (instance == null)
		{
			lock (_lock)
			{
				// create the instance only if the instance is null
				if (instance == null)
				{
					instance = new Singleton();
				}
			}
		}

		// Otherwise return the already existing instance
		return instance;
	}
}

Now what we have is a class that will acquire lock only for first instance creation and rest of the time, it will return the already created instance.

Using the .NET CLR Capabilities for Thread Safety

When we are using C#, we can utilize the CLR behaviour to have a thread safe implementation without the complexity of locking. What we could do is that we could include a static constructor in the class that will take care of the instance creation. The static constructor of a class is called when either the first static member of the class is accessed (in our case, it will be GetInstance method) or the first instance of the class is created (which is not a valid scenario here as constructor is private). So let's look at the implementation with the following changes:

C#
public sealed class Singleton
{
	// A private constructor to restrict the object creation from outside
	private Singleton()
	{

	}

	// A private static instance of the same class
	private static readonly Singleton instance = null;

	static Singleton()
	{
		// create the instance only if the instance is null
		instance = new Singleton();
	}

	public static Singleton GetInstance()
	{
		// return the already existing instance
		return instance;
	}
}

So what we have done here is that we have moved the instantiation in the static constructor which will get called when the GetInstance method will be called. Static constructor will create the instance and that instance will get returned by the GetInstance method.

The instance field has been marked as readonly so that it can only be instantiated during static initialization. And now we have a fairly usable singleton class that is thread safe without the performance overhead of locks.

Note: One might argue that in our last version, the initialization is not lazy as if this class has any other static member, then the instance will get created even if it is not requested. There is one more version of singleton possible where this can be circumvented using either nested class or Lazy<T><t>. But I am not going to discuss them here. In most cases, a singleton will not have other static methods. If we find ourselves in a scenario where we have a singleton that also has other static methods, perhaps we are violating Single Responsibility Principle and should revisit our class design again.

Point of Interest

Although this stuff is very basic and is repeatedly covered by many texts. You will find the code snippets in all the singleton implementations also the same as there are not many possible implementations of this pattern with C#. Still, I thought it could really be useful to put an explanation of the pattern in my own words for the guys who are just at the starting with this pattern. For more advanced readers, I recommend reading this blog for much more detailed explanation of this pattern: C# in Depth: Implementing the Singleton Pattern[^]

History

  • 20th January, 2016 - undeleted - Someone might benefit from the explanation
  • 2013 - Deleted - similar implementation/code exists in all singleton documentation
  • 2012 - First version

License

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