Click here to Skip to main content
15,898,222 members
Articles / .NET

Different Ways to Implement Singleton in .NET (and Make People Hate You Along the Way)

Rate me:
Please Sign up or sign in to vote.
3.83/5 (17 votes)
28 Sep 2017CPOL4 min read 17.5K   19   5
Here are different ways to implement Singleton in .NET

Code that accompanies this article can be downloaded here.

The Singleton Pattern is probably the most well-known design pattern 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 the 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 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 were 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 Dependency 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

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 few hits that will suggest an implementation that looks like this:

C#
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 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 the 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:

C#
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 the 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 is instance 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 flow with if-null combos is not such a good idea and that it indicated 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:

C#
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 property Instance will trigger static constructor, also known as type initializer. Other threads that try to read the Instance property will be locked until static constructor has finished. Only once it completes its task, other threads will be allowed to get 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, e.g., 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 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:

C#
using System;

namespace SingletonExamples
{
    public class Singleton
    {
        private static readonly Lazy<Singleton> instance =
        new Lazy<Singleton>(() => 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 implementation. It is simplest, thread-safe solution with lazy initialization, that everyone can understand. Also, I need to add once again that first implementation shouldn’t be used ever.

Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License.

License

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


Written By
Software Developer (Senior) Vega IT Sourcing
Serbia Serbia
Read more at my blog: https://rubikscode.net

Comments and Discussions

 
QuestionThread safe implementation Pin
Member 1045734729-Sep-17 20:39
Member 1045734729-Sep-17 20:39 
QuestionSome threading concerns Pin
wkempf13-Jun-17 7:01
wkempf13-Jun-17 7:01 
You describe using the double-checked locking pattern (DCL) without naming it. You shouldn't have. The DCL is, in general, broken. With the right tools and the right knowledge (.NET does give you the tools, but you'd best acquire the knowledge before even considering this) you *can* implement the DCL correctly, but rarely is it worth it. The DCL should mostly be considered an anti-pattern.

You say that static constructors can lead to dead-lock, but you provide no source or proof for this assertion. I don't believe it to be true. At least, no more so than ANY synchronization tool. Certainly it can be no more likely to cause deadlocks than use of Lazy. I can conceive of ways to create deadlocks with either, but they are contrived examples that you're unlikely to ever actually code.
PraiseRe: Some threading concerns Pin
Evgeny N22-Jun-17 15:52
Evgeny N22-Jun-17 15:52 
GeneralAnything new? Pin
PIEBALDconsult11-Jun-17 15:03
mvePIEBALDconsult11-Jun-17 15:03 
GeneralRe: Anything new? Pin
Bernhard Hiller29-Sep-17 3:06
Bernhard Hiller29-Sep-17 3:06 

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.