The Singleton is a creational design pattern which allows us to create a single instance of an object and to share that instance with all the users that require it. There is a common opinion that the Singleton pattern is not recommended because it presents a code smell, but there are some cases where it fits perfectly.

For example, some components have no reason to be instanced more than once in a project. Take a logger for example. It is quite common to register logger class as a singleton component because all we have to do is to provide a string to be logged and the logger is going to write it to the file. Then multiple classes may require to write in the same file at the same time from different threads, so having one centralized place for that purpose is always a good solution.

If you want to see a logger in action in ASP.NET Core Web API, you can read this article: ASP.NET Core – Logging with NLog.

Or maybe sometimes we have a task to read some data from a file and use them through our project. If we know for sure that file won’t change while we read it, we can create a single instance of the object which will read that file and share it through the project to the consumer classes.

In this article, we are going to show you how to properly implement a Singleton pattern in your project. When we say properly we mean that our singleton class is going to be a thread safe which is a crucial requirement when implementing a Singleton pattern.

So, let’s begin.

The source code is available at the Singleton Design Pattern – Source Code.

This article is divided into the following sections:

Initial Project

We are going to start with a simple console application in which we are going to read all the data from a file (which consist of cities with their population) and then use that data. So, to start off, let’s create a single interface:

After that, we have to create a class to implement the ISingletonContainer interface. We are going to call it SingletonDataContainer:

So, we have a dictionary in which we store the capital names and their population from our file. As we can see, we are reading from a file in our constructor. And that is all good. Now we are ready to use this class in any consumer by simply instantiating it. But is this really what we need to do, to instantiate the class which reads from a file which never changes (in this particular project. Population of the cities is changing daily). Of course not, so obviously using a Singleton pattern would be very useful here.

So, let’s implement it.

Singleton Implementation

To implement the Singleton pattern, let’s change the SingletonDataContainer class:

So, what we’ve done here is that we hid our constructor from the consumer classes by making it private. Then, we’ve created a single instance of our class and exposed it through the Instance property.

At this point, we can call the Instance property as many times as we want, but our object is going to be instantiated only once and shared for every other call.

Let’s check that theory:

If we start our app, we are going to see this:

Singleton result

We can see that we are calling our instance four times but it is initialized only once, which is exactly what we want.

But our implementation is not ideal. Let’s construct our object the lazy way.

Implementing a Thread-Safe Singleton

Let’s modify our class to implement a thread-safe Singleton by using the Lazy type:

Right now, our class is completely thread-safe. It is loaded in a lazy way which means that our instance is going to be created only when it is actually needed. We can even check if our object is created with the IsValueCreated property if we need to.

Excellent, we have finished our Singleton implementation.

Now we can fully consume it in our consumer class:

Great job.

Conclusion

We have seen that even though the Singleton pattern isn’t that much appreciated, it can be helpful in some cases. So, it is always up to us to decide whether we are going to use it or not. Bottom line is that if we need to apply a Singleton pattern in our project, this is a good way to do it.

If you have enjoyed reading this article and if you would like to receive the notifications about the freshly published .NET Core content we encourage you to subscribe to our blog.