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

The Singleton design pattern is one of the most widely used design patterns in software development. It is a creational pattern that ensures a class has only one instance while providing a global access point to this instance. In this blog post, we 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

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 logging, shared objects, caching, thread pool, and database connections.

Use Cases

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

  • When you want to control the number of instances of a class that can be created.
  • When you want to have a single instance of a class that can be accessed 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
  • When you need to have a single instance of a class that is responsible for initializing resources shared by other objects.
  • When resources are expensive and only one instance of a class is needed to manage those resources.

Singleton Class Structure in C#

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

  • A private constructor to prevent instantiation of the class from outside the class.
  • 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 public method that can be used to perform some action on the singleton instance.

Example:

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 full working code that 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 uses the Double Check Locking method which uses a double-checked 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 actually needed. This is helpful in situations where the singleton object requires a lot of resources and it 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 it is initially requested by a user or program. 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 the instance of a class as soon as the class is loaded in the memory. This approach is useful when the singleton object is lightweight and must be created regardless of whether it is used or not.

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 is useful for saving resources and maintaining 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 instance of the class is created, even in a multi-threaded environment.

The volatile keyword is used to ensure that the instance is created only once, and the lock statement is used to provide 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 be used to provide a single and only one access point to a global resource that can be shared across the application.
Proxies for Services:The process of 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. By using a Singleton for caching, you can store the data in memory for quick access by other parts of the application. This can greatly 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 not always be the best choice as it can result in tight coupling, making it difficult to test and maintain the code. Therefore, it should be used 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, but here Singleton is not only allowing to create an instance of the class but also makes that instance available for the whole application to use.
  • Hard to test and maintain: Because of the global access point and tight coupling, it makes 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 own instance, and it 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. This can make it challenging for developers to make changes to the class without affecting the clients.

Conclusion

The Singleton design pattern is a powerful and widely used design pattern in software development. It ensures that a class can have only one instance which can be accessed throughout the whole application. In this blog post, we have discussed the use cases of the Singleton design pattern, and also the three different ways to implement it in our C# code: 01. Lazy Initialization, 02. Eager Initialization, and 03. Double Check Locking. It is important to note that when we are going to 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 useful 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 only one instance of a class is needed 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, a Singleton class can be serialized in C#, but it’s important to consider that deserialization will create a new instance of the class, which is 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 or you can 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.

5 3 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments