Singleton Design Pattern in .NET C#

What is Singleton Pattern in C#?

A design approach known as the singleton pattern limits a class's instantiation to a single object while still allowing access to the object. When precisely one item is required to coordinate actions throughout the system, this is helpful. Therefore, in order to guarantee that a single instance of a given class will be produced and to grant easy global access to that instance for the duration of the program, we must utilize the Singleton Design Pattern in C#.

Guidelines of Singleton Design Pattern

A constructor that is both private and parameterless must be declared. Because it will prevent the class from being instantiated from outside the class, this is necessary. It can only be instantiated within the same class.

To make sure the class cannot be inherited, it should be marked sealed. When working with the nested class, this will come in handy.

The singleton instance of the class must be referenced by a private static variable that we must construct.

A public static property or function that returns the class's singleton instance must also be created. The first thing this method or property does is see if a singleton class instance has been created. It returns the singleton instance if one has been generated; if not, it will construct an instance and then return it.

An example of a C# singleton design pattern

Let's examine some examples to better grasp the C# Singleton Design pattern. The Singleton Design Pattern in C# can be applied in a variety of ways. They are listed below. We'll go over each of the following approaches to using the C# Singleton Design Pattern.

  • In C#, there is no thread-safe singleton design pattern.
  • Implementation of a Thread-Safe Singleton with Lock.
  • Double-check locking is used to implement the Thread-Safety Singleton Design Pattern.
  • Implementing the Thread-Safety Singleton Design Pattern with Eager Loading.
  • The Lazy<T> Generic Class is Used in the Singleton Design Pattern to Implement Lazy Loading.

There Is No Thread-Safe Singleton Design Pattern in C#

The implementation of the No Thread-Safe Singleton Design Pattern in C# will be covered in this article. We'll go over each of the remaining implementations in detail in our next posts. Let's look at an example of how to apply the No Thread Safe Singleton Design Pattern in C#. Make sure you have a class file called Singleton.cs before copying and pasting the code below.

public sealed class Singleton
{
    private static int Counter = 0;

    private static Singleton Instance = null!;

    public static Singleton GetInstance()
    {
        if (Instance == null)
        {
            Instance = new Singleton();
        }

        return Instance;
    }

    private Singleton()
    {
        Counter++;

        PrintDetails($"Counter Value: {Counter}");
        Console.WriteLine();
    }

    public void PrintDetails(string message)
    {
        Console.WriteLine(message);
    }
}

In this case, the Singleton class was constructed as sealed, meaning that inheritance from derived classes is prohibited. To prevent the class from being instantiated from outside the class, a private parameterless constructor is used while creating the class. However, we are able to make instances of the same class. To ensure that only one class instance will be produced based on the null condition, we once again designated the instance variable private and populated it with the null value. By examining the value of the private variable instance, the public function GetInstance retrieves a single instance of the class. Through the singleton instance, the public method PrintDetails can be called from outside the class.

Singleton profile = Singleton.GetInstance();
profile.PrintDetails("C# Corner Profile");

Singleton admin = Singleton.GetInstance();
admin.PrintDetails("C# Corner Admin");

Get the GetInstance static method

Even though we called the GetInstance method twice and reported the counter value as 1, the output above makes it evident that the private constructor is only invoked once. Thus, it demonstrates that a singleton instance is only ever created once. In the example above, we are not implementing the singleton design pattern in a thread-safe manner. It implies that it can produce numerous instances of the singleton class in a multithreaded environment.

Advantages of Singleton Design Pattern

  • Utilizing the singleton design pattern in C# has several benefits, the primary one being that it manages concurrent access to the shared resource. This indicates that the singleton design pattern effectively manages concurrent access to a resource if it is shared with numerous clients at once.
  • It has static initialization and is capable of lazy loading.
  • sharing master and configuration data, which are common data and are not often updated in an application. In that scenario, we must cache the memory-based objects.
  • Because it offers a single global access point to a specific instance, it is simple to maintain.
  • To lessen the overhead associated with repeatedly instantiating a large object.

Disadvantages of Singleton Design Pattern

Unit testing is a significant challenge since it adds a global state to a program.

Because you must utilize locking to serialize the object in order to access the singleton instance in a multi-threaded environment, it lowers the possibility of parallelism within a program.

When to Use Singleton Design Pattern in C#?

Handling Shared Resources: Singletons can be used to handle shared resources like:

  • A pool of database connections.
  • A file manager capable of managing all file-related tasks.
  • A cache is used by several application components when they need to store and retrieve objects.

Configuration Settings

When an application-wide configuration object needs to be accessed from several locations, a Singleton can be used to store and retrieve its configuration settings.

Logging

Messages sent throughout the application can be recorded using a Singleton logger class. Using a Singleton makes sense to prevent conflicts and guarantee consistency, as logging usually entails publishing to a single resource (such as a file or console).

Hardware Interface Access

A Singleton can guarantee coordinated access when interacting with hardware resources such as printers or serial ports, averting conflicts that may arise from many points of access.

Performance considerations

Certain classes require a lot of resources to create an instance of. Singleton is an excellent option if these kinds of instances are used frequently because it is more efficient to create them once and reuse them.

When Not to Use Singleton Design Pattern in C#?

  • Testing Difficulties: Because singletons maintain a state between tests, unit testing might be challenging. It may become difficult to pinpoint problems due to tests that are not independent as a result of this state's persistence.
  • Global State Management: Using a singleton creates a global state in your program, which may result in unnoticed dependencies between different classes and increase the complexity and unpredictability of the system.
  • Concurrency Problems: When singletons are used in multithreaded applications, they may cause synchronization and concurrency problems, especially if the singleton state is changeable.
  • Flexibility and Scalability Limitations: Scalability and flexibility may be restricted by singletons. As the application expands, they frequently turn into bottlenecks, and because of their widespread influence, altering the Singleton implementation can be difficult.
  • Overuse and Misuse: Without fully grasping the ramifications, developers frequently overuse singletons when searching for an easy way to guarantee that a class has just one instance. When used improperly, it might result in design issues that don't show up until much later in the process.

We learned the new technique and evolved together.

Happy coding! 😊