Different ways to implement Singleton in .NET (and make people hate you along the way)

Nikola Zivkovic Categories: Design patterns and principles Date 14-Jun-2017
Different Ways To Implement Singleton In .NET (And Make People Hate You Along The Way)

Table of contents

    The Singleton Pattern is probably the most well-known design patterns that came out of Gang of Four’s book Design Patterns: Elements of Reusable Object-Oriented Software. This pattern is one of the creational patterns, and basically, it ensures that only one object of a particular class is created and shared among other members of the system. Singleton class should enable easy access to its only instance to other classes.
    But this design pattern carries a lot of controversies too. Some consider it an antipattern and cause of code smell. Among many complaints, people often argue that it violates the Single Responsibility Principle, due to the fact that it handles its own creation, that it couples code and that it is hard to test. And even though some of these issues have been addressed by Uncle Bob himself, there are a lot of good points that Singleton class shouldn’t be used. Heck, there is a good chance that people will hate you just by writing one. But…

    Singleton patterns still solve one problem that you may encounter – Resource Contention. This is a situation where you need one instance of the object and you need to manage that instance. There are not many cases of this situation and one example of this is a single log file. There are suggestions that you can solve this problem with Dependancy Injection which you should also consider. But, in case you need Singleton, let’s take a look at some good and bad ways to implement Singleton class.

    Standard implementation

    The Singleton pattern is also one of the most commonly asked interview questions. Usually, candidates are asked to write one version of singleton implementation. If you Google this you’ll probably find a few hits that will suggest an implementation that looks like this:

    using System;namespace SingletonExamples{ // Broken, non thread-save solution. // Don't use this code. public class Singleton { private static Singleton _instance; private Singleton() { } public static Singleton Instance { get { if (_instance == null) { _instance = new Singleton(); } return _instance; } } }}

    Now this will probably pass as a fine answer on an interview, but this code definitely has a lot of problems, apart from not being a very impressive one. The biggest problem is that this code isn’t thread-safe, and that is why you shouldn’t use this code. Yes, now that you are using threads and Singleton and everyone will avoid you in the office. Nevertheless, let’s go through this thought exercise. We don’t want to end up in a situation where two threads evaluate if (_instance == null) as true and each creates an instance of the class.

    Thread-safe implementation

    So, let’s do something like this:

    using System;namespace SingletonExamples{ public class Singleton { private static Singleton _instance; private static readonly object _lock = new object(); private Singleton() { } public static Singleton Instance { get { lock (_lock) { if (_instance == null) { _instance = new Singleton(); } return _instance; } } } }}

    There it is: we used locks to make our singleton class thread-safe. But, locks are not very good synchronization mechanisms in this case. Because a lock is required everytime Instance is asked for, the performance of this code will be degraded. This problem can be avoided if we ask if the instance is null before locking and then asking if the instance is null once again after acquiring the lock. Now, that would look ugly. Also, we already have one if-null combo, and we can agree that controlling the flow with if-null combos is not such a good idea and that it indicates that we have problems in our design.

    Can we try to use the static constructor?

    Implementation with static constructor

    Static constructors will assure that it has been run only once per application domain, meaning that our Singleton class can look like this:

    public class Singleton{ private static Singleton instance; private Singleton() { } static Singleton() { instance = new Singleton(); } public static Singleton Instance { get { return instance; } }}

    The first thread that wants to get the Instance property will trigger the static constructor, also known as type initializer. Other threads that try to read the Instance property will be locked until the static constructor has finished. Only once it completes its task, other threads will be allowed to get the Instance value. So, locking on every time someone tries to get an instance is avoided.

    But…people will have a lot of comments on that static constructor of yours. Usually something along the line that they could cause deadlocks if you perform blocking operations, eg. asynchronous callbacks.

    Can we avoid this? If we are working in C# 4 or above, we can. And we can achieve this by using – Lazy.

    Lazy implementation

    Lazy initialization of an object means that object creation is deferred until it is first used. This way of object construction is used primarily for optimization purposes. In .NET 4 and above, we can use the Lazy class, which encapsulates this kind of behavior. It is also thread-safe, so we don’t have to worry about multiple threads creating duplicate objects.

    So, Singleton implementation using Lazy would look like this:

    using System;namespace SingletonExamples{ public class Singleton { private static readonly Lazy instance = new Lazy(() => new Singleton()); public static Singleton Instance { get { return instance.Value; } } private Singleton() { } }}

    Conclusion

    Singleton is for sure one pattern with many flaws. The problem is also that this pattern is often used in places not quite suited for it, thus coupling code, and adding performance issues. However, it has its purpose and its (rare) use.

    And although there are multiple variations of Singleton implementation, I personally prefer the last version of the implementation. It is the simplest, thread-safe solution with lazy initialization, that everyone can understand. Also, I need to add once again that the first implementation shouldn’t be used, ever.

    nikola-z-ivkovic-_authorsphoto.png
    Nikola Zivkovic Team Lead & Scrum Master

    Nikola is a big fan of extreme programming practices and agile methodologies. He is proficient in several programming languages and frameworks, but prefers .NET technologies. Read more his texts here.