Singleton Design Pattern in C#: A Beginner’s Guide with Examples

The Singleton design pattern is one of the most commonly used software development design patterns. It is a creational pattern that ensures a class can have only one instance while providing a global access point to this instance.

This blog post will explore the Singleton design pattern in C#, its use cases, and various ways to implement it.

Singleton-Design-Pattern-in-CSharp
Singleton Design Pattern in C#

What is the Singleton Design Pattern in C#?

A Singleton pattern is a design pattern that ensures a class has only one instance throughout the lifetime of an application, and it provides a global access point to that instance. It is often used for loggingshared objectscachingthread pool, and database connections.

Example: Non-thread-safe Singleton Class

In the following code, the getInstance() property creates a Singleton object when called for the first time and subsequently returns the same object. However, it’s important to note that this example does not implement thread safety. If multiple threads run simultaneously, two Singleton objects can be created.

// This singleton is not thread-safe.
public sealed class Singleton
{
  private static Singleton obj = null;

  // private constructor.
  private Singleton()
  {
  }

  // public static property for creating a single instance.
  public static Singleton getInstance
  {
    get
    {
      if (obj==null)
      {
        obj = new Singleton();
      }
      return obj;
    }
  }
}

Singleton: Use Cases

The Singleton design pattern is commonly used in the following scenarios:

  • When you want to control the number of class instances to be created.
  •  When you want to have a single instance of a class that you can access from multiple threads.
  •  When only a single instance of a class is needed to control the action throughout the execution.
  •  When you want to maintain only one copy of the shared data
  •  You need to have a single instance of a class responsible for initializing resources shared by other objects.
  •  When resources are expensive, and you want only one instance of a class to manage those resources.

Singleton Class Structure in C#

A class should have the following structure to achieve a singleton design pattern:

  • A class should have a private constructor to prevent the instantiation of that class from outside the class.
  •  It would be best if the class had a private static instance variable to store the single instance of the class.
  •  A public static property to provide global access to the instance.
  •  A private static object is used for thread-safe initialization of the instance (if needed).
  •  A private static readonly instance variable that ensures the object is initialized only once when it is first called.
  •  A private static Lazy<T> instance variable that ensures the object is initialized only when it is first requested.
  •  A private static volatile instance variable that will ensure the object will be initialized only once when it is first called and also handle the multiple threading scenarios.
  •  A class should have a public method to perform some action on the singleton instance.

Example: Thread Safe

using System;
public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    private static object syncRoot = new object();
    private static Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());
    private static volatile Singleton vInstance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }

    public static Singleton Instance_v1
    {
        get
        {
            if (vInstance == null)
            {
                lock (syncRoot)
                {
                    if (vInstance == null)
                        vInstance = new Singleton();
                }
            }
            return vInstance;
        }
    }

    public static Singleton Instance_v2
    {
        get
        {
            return lazy.Value;
        }
    }

    public void Print()
    {
        Console.WriteLine(" Print from Singleton\n");
    }
}
public class Program
{
    public static void Main()
    {
      Singleton Instance =  Singleton.Instance;
      Singleton Instance_v1 = Singleton.Instance_v1;
      Singleton Instance_v2 = Singleton.Instance_v2;

        Console.WriteLine(" Instance using Eager Initialization method:");
        Instance.Print();
        Console.WriteLine(" Instance_v1 using Double Check Locking method:");
        Instance_v1.Print();
        Console.WriteLine(" Instance_v2 using Lazy Initialization method:");
        Instance_v2.Print();

        Console.ReadKey();
    }
}

Output:

Singleton-design-pattern-example-in-csharp-output
Singleton design pattern example in C#

Code Explanation:

The above code is a complete working code you can use in your application.

It has the following three different methods to create a singleton class.

  • The first Singleton Instance uses the Eager Initialization method, which is created as soon as the class is loaded.
  •  The second one is Instance_v1, which uses a double-check locking mechanism to ensure that only one instance of the class is created, even in a multi-threaded environment.
  •  The third one is Instance_v2 uses the Lazy Initialization method, which creates the instance only when it is first requested.

Implementing the Singleton Design Pattern in C#

The following are three ways to implement the Singleton design pattern in C#:

01. Singleton Class with Lazy Initialization

The lazy initialization technique delays the creation of a class instance until it is needed. It is helpful in situations where the singleton object requires a lot of resources and is not always necessary to create it.

Example:

// sealed class cannot be inherited
public sealed class LazySingleton
{
    // Static Lazy<T> instance variable used for Lazy initialization of the instance
    private static Lazy<LazySingleton> lazy = new Lazy<LazySingleton>(() => new LazySingleton());

    // Public property provides global access to the instance
    public static LazySingleton Instance { get { return lazy.Value; } }

    // Private constructor prevents instantiation of the class from outside the class
    private LazySingleton()
    {
    }

    //Method that can be used to perform some action on the singleton instance
    public void Print()
    {
        Console.WriteLine("Print from LazySingleton");
    }
}

The Lazy singleton design pattern utilizes the Lazy Initialization technique to only create the class instance when a user or program initially requests it. This approach ensures thread safety in the creation of the singleton pattern.

The Lazy<T> object of the singleton class is employed to postpone the creation of the object until it is required for the first time.

02. Singleton Class With Eager Initialization

The Eager initialization method creates an instance of a class as soon as the class is loaded in memory. This approach is practical when the singleton object is lightweight and must be created regardless of its use.

Example:

/* EagerSingleton class is a singleton class that creates an instance 
 of itself at the time of class loading
 and provides a global point of access to that instance */
using System;
public sealed class EagerSingleton
{
    // private static readonly field that holds the instance of the class
    private static readonly EagerSingleton instance = new EagerSingleton();

    // Static property that returns the instance of the class
    public static EagerSingleton Instance { get { return instance; } }

    // private constructor to prevent instantiation of the class from outside
    private EagerSingleton()
    {
    }

    // Method to demonstrate the functionality of the singleton class
    public void Print()
    {
        Console.WriteLine("Print from Eager Singleton");
    }
}

03. Singleton Class With Double Check Locking

The double-check locking method is a technique that is used to ensure that only one instance of a class is created, even in a multi-threaded environment, by adding a check when multiple threads try to access the object simultaneously. It helps save resources and maintain performance.

Example:

public sealed class DoubleCheckSingleton
{
    //volatile keyword ensures that the instance is created only once even in a multi-threaded environment
    private static volatile DoubleCheckSingleton instance;

    //object used for thread-safe initialization of the instance
    private static object syncRoot = new object();

    // Public property provides global access to the instance
    public static DoubleCheckSingleton Instance
    {
        get
        {
            //Double-checked locking mechanism to ensure that only one instance of the class is created
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new DoubleCheckSingleton();
                }
            }
            return instance;
        }
    }

    //Private constructor prevents instantiation of the class from outside the class
    private DoubleCheckSingleton()
    {
    }

    //Method that can be used to perform some action on the singleton instance
    public void Print()
    {
        Console.WriteLine("Print from DoubleCheckSingleton");
    }
}

This Double Check Locking Singleton code uses the Double Check Locking method to ensure that only one class instance is created, even in a multi-threaded environment.

The volatile keyword ensures that the instance is created only once, and the lock statement provides thread safety.

It’s a best practice when working with multi-threading to use thread-safe techniques to prevent race conditions.

Advantages of Singleton Design Pattern

The following are the few advantages of using the Singleton design pattern.

(Singleton) AdvantageDescription
Ensures a single instance of a class:The singleton design pattern ensures that a class can have only one instance created throughout the lifetime of an application, and it provides a global access point for that instance.
Single access point to a global resource:The singleton pattern can provide a single and only one access point to a global resource that can be shared across the application.
Proxies for Services:Creating a Service client to invoke the service API in an application is a complex operation and the most time-consuming process. However, making the Service proxy, a Singleton can significantly enhance the performance of our application.
Reduce resource consumption:It can reduce resource consumption by only initializing the object when it’s needed.
Facades:Creating Database connections as Singletons can enhance the application performance.
Data sharing:Storing constant or configuration values in a Singleton object allows other application components to access them.
Logging:Using a Singleton for logging can improve the performance of an application by creating a single instance of the logger class, thereby reducing I/O operations and providing a consistent/unified logging system throughout the application.
Caching:Retrieving data from a database multiple times can slow down your application. Using a Singleton for caching, you can store the data in memory for quick access by other application parts. It can significantly improve performance by reducing the number of database calls.
Advantages of Singleton design Pattern

It’s important to note that using the Singleton pattern may only sometimes be the best choice as it can result in the tight coupling, making it difficult to test and maintain the code. Therefore, we should use it with caution.

Disadvantages of Singleton Design Pattern in C#

The following is a list of a few disadvantages of using the Singleton pattern.

  • Violates Single Responsibility Principle: The Singleton pattern violates the SRP rule, which says that a class should perform only one specific job. Still, here, Singleton allows the creation of an instance of the class and makes that instance available for the whole application to use.
  • Hard to test and maintain: The global access point and tight coupling make it harder to test and maintain the code.
  • Violates Open/Closed Principle: Singleton class violates the Open/Closed Principle as it is responsible for creating its instance and is not open for extension.
  • Can lead to tight coupling: The Singleton pattern can result in a tight coupling between the class and its clients. It can make it challenging for developers to change the class without affecting the clients.

Conclusion

The Singleton design pattern is powerful and widely used in software development. It ensures that a class can have only one instance, which we can access throughout the application. In this blog post, we have discussed the use cases of the Singleton design pattern and the three different ways to implement it in our C# code: 01. Lazy Initialization02. Eager Initialization, and 03. Double Check Locking. It is important to note that when we implement a singleton pattern in a multi-threaded environment, we must use thread-safe techniques to prevent race conditions.

FAQ

The following is the list of some frequently asked questions and answers about the Singleton design pattern:

Q: What is a Singleton design pattern in C#?

The singleton design pattern is one of the best-known and widely used patterns in software engineering. A singleton is a class that only allows a single instance of itself to be created and usually gives simple access to that instance throughout the entire application.

Q: Why should you use a Singleton pattern in C#?

The Singleton pattern can be helpful in situations where only a single instance of a class is needed to control the action throughout the execution or when resources are expensive. And we have only one instance of a class to manage those resources.

Q: How do you create a Singleton class?

01. Declare the constructor of the class as private to prevent external instantiation.
02. Create a private static instance of the class.
03. Create a public static method that returns the instance of the class.

Q: Can a Singleton class be inherited in C#?

No, a Singleton class cannot be inherited as it contains a private constructor.

Q: How can you handle thread safety in a Singleton class in C#?

To handle thread safety in a Singleton class in C#, you can use the lock statement to synchronize access to the shared resource.

Q: Can a Singleton class be serialized in C#?

Yes, we can serialize a Singleton class in C#. Still, it’s important to consider that deserialization will create a new class instance, again breaking the Singleton pattern.

Q: How can you handle lazy initialization in a Singleton class in C#?

To handle lazy initialization in a Singleton class in C#, you can use the Lazy<T> class. You can also implement it by adding a private static member variable that is initialized only when the class is first used.

References: CSharpindepth- Singleton pattern in C#

Articles you might also like:

We would love to hear your thoughts on this post. Please leave a comment below and share it with others.

c20e93cf99b4a0eb1e4a099de6c2c300?s=250&r=g
5 3 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments