Skip to main content

Singleton Design Pattern and different ways to implement it in C#

The singleton pattern is one of the best-known patterns in software engineering. In a singleton pattern, we ensure that the class has only one instance and we provide a simple and global point of access to this object. This is useful when we require exactly one object of a class to perform our operations.

Singleton classes don't allow any parameters to be specified when creating the instance because a second request for an instance but with a different parameter could be problematic.

In this article, I'll provide you with a real-time example, a Comparison of Singleton with Static class, a UML class diagram of Singleton, and then the implementation of Singleton in various ways.

Real-time example:

The practical implementation of the Singleton design pattern can be seen in various applications used by us. Take the example of Microsoft word, there is only one instance of the word application active at a time even though the user opened multiple documents at a time. And all the requests for different word documents are handled by a single instance.

Singleton versus Static Class:

Singletons and Static classes both provide sharing of redundant objects in memory, but they differ in usage and implementation. Mentioned below are some points one should consider before making a decision:

  • Singletons preserve the conventional class approach and don't require that you use the static keyword everywhere, while static class requires all members should be static.
  • Singleton may be more demanding to implement at first, but will greatly simplify the architecture of your application as compared to static class.
  • Singleton requires a single private and parameter-less constructor, while a static class can only have a static constructor.
  • Unlike static classes, one can use a singleton as a parameter to methods, or objects.
  • In the case of the Singleton class, there should be at most one object through which we can access the class members, while in the case of the Static class we needn't any object to access class members.
  • Singleton object is created lazily, i.e. the instance isn't created until it is first needed. On the other hand, the static class is loaded into memory as soon as the application is initialized.

UML class diagram

UML class diagram for the Singleton pattern is given below.



Implementation:

In the case of the Singleton pattern, there is a single private and parameter-less constructor. This prevents other classes from instantiating it. It also prevents subclassing because if a singleton can be subclassed and if each of those subclasses can create an instance that means a violation in the pattern. Other than that there is a static variable (or we can have a method as well) that holds a reference to the single created instance. And on top of that a public static means of getting the reference to the single created instance.

Here we'll see different ways of implementing the singleton pattern in C#.

A simple version of Singleton:

It is not thread-safe, i.e. two different threads may create two instances.

/// <summary>
/// Bad way to implement Singleton
/// </summary>
public class Singleton
{
    private static Singleton _instance = null;

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }
}

Singleton with simple thread safety:

In this implementation, the lock is added to make Singleton thread-safe. In this case, the thread takes out a lock and then checks if the instance already exists or not before creating the new instance. This ensures that only one thread will create an instance as only one thread can be in that part of the code at a time - by the time another thread enters, the first thread will have created the instance. But there is a performance overhead as a lock is acquired every time the instance is requested.

/// <summary>
/// Singleton with thread safety
/// </summary>
public class Singleton
{
    private static Singleton _instance = null;
    private static readonly object synclock = new object();

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            lock (synclock)
            {
                if (_instance == null)
                {
                    _instance = new Singleton();
                }
                return _instance;
            }
        }
    }
}

Singleton with thread-safety using double-checks locking:

This implementation attempts to be thread-safe along with avoiding taking a lock every time.

/// <summary>
/// Singleton with thread safety using double check
/// </summary>
public class Singleton
{
    private static Singleton _instance = null;
    private static readonly object synclock = new object();

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (synclock)
                {
                    if (_instance == null)
                    {
                        _instance = new Singleton();
                    }
                }
            }
            return _instance;
        }
    }
}

Singleton with thread safety without using locks:

This is another version of thread-safe Singleton, but without using locks. This implementation is faster than adding extra checking as in the above example. But this implementation is not as lazy as the other implementations (as we are using a static constructor).

/// <summary>
/// Thread safe Singleton without lock
/// </summary>
public class Singleton
{
    private static readonly Singleton _instance = new Singleton();

    /// <summary>
    /// Explicit static constructor to tell C# compiler
    /// not to mark type as beforefieldinit
    /// </summary>
    static Singleton()
    {
    }

    private Singleton()
    {
    }

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

Singleton with full lazy instantiation:

To fix the problem mentioned in the above example, we can modify the code and create a private class inside the Singleton class and that'll allow full lazy instantiation along with all the performance benefits.

/// <summary>
/// Thread safe Singleton with full lazy instantiation
/// </summary>
public class Singleton
{
    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return Nested._instance;
        }
    }

    private class Nested
    {
        /// <summary>
        /// Explicit static constructor to tell C# compiler
        /// not to mark type as beforefieldinit
        /// </summary>
        static Nested()
        {
        }

        internal static readonly Singleton _instance = new Singleton();
    }
}

Singleton with .Net Lazy<T>:

If you're implementing Singleton in .NET 4.0 (or higher versions), you can use the System.Lazy<T> type to make the lazy instantiation. You can easily write the code with the help of lambda expression and you just need to pass a delegate to the constructor which calls the constructor of the Singleton class. It's easy to write and understand and also performs well. You can also use the IsValueCreated property (in the .Net 4.5 frameworks) to check whether or not the instance has been created yet.

/// <summary>
/// Singleton with Lazy<T>
/// </summary>
public class Singleton
{
    private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());

    private Singleton()
    {
    }

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


📑 Singletons allow you to reuse code and control object states much easier.

✔️ We should go with Singleton only when exactly one instance is required.

✔️ There are various ways of implementing the singleton pattern in C#. One has to decide on performance along with laziness while creating the Singleton.

✔️ Like if someone wants to go with thread safety, then can go with either option 2 or 3(with double check).

✔️ But if you choose performance over laziness and don't want to use locking then probably you'll go with the fourth option.

✔️ However, if you want to go with lazy instantiation and don't want to use locks as well, then options 5 or 6 are good to go. But option 6 can be used in .Net 4.0 or higher versions.

Comments

Popular posts from this blog

Error 405 : ASP.NET Core Web API PUT and DELETE Methods not allowed

Recently, while working with .Net core API I came across the issue of “Error 405 — Methods not Allowed” After some research, I found out that both GET and POST requests working fine but neither PUT nor DELETE requests working. Another thing is that the PUT and DELETE request was also working fine on my local machine but failed when we host on our Azure server. When I explored the issue on the web it led me to the conclusion that WebDAVModule seems to set PUT and DELETE request methods disabled by default and due to that PUT and DELETE throw 405 errors. To make the PUT and DELETE requests work, we need to override the WebDAVModule setting in web.config file by adding the below settings under “ system.webServer ”. < system.webServer >   < modules runAllManagedModulesForAllRequests = " false " >     < remove name = " WebDAVModule " />   </ modules > </ system.webServer > There may be 2 web.config files in your

C#: Merging Excel cells with NPOI HSSFWorkbook

In this post we’ll see how to merge the two or more cell with each other while creating the excel sheet using NPOI . Mentioned below is code to merge multiple cells, in this example we are merging first cell to fifth cell of first row (you can adjust row or cell range by passing particular parameters in CellRangeAddress). //Created new Workbook var hwb = new NPOI.HSSF.UserModel. HSSFWorkbook (); //Create worksheet with name. var sheet = hwb.CreateSheet( "new sheet" ); //Create row and cell. var row = sheet.CreateRow(0); var cell = row.CreateCell(0); ; //Set text inside cell cell.SetCellValue( "This is Merged cell" ); cell.CellStyle.WrapText = true ; //define cell range address // parameters: -> first row to last and first cell to last cell var cra = new NPOI.SS.Util. CellRangeAddress (0, 0, 0, 4); //Add merged region to sheet. sheet.AddMergedRegion(cra); Hope this solution helps you J

How to set Swagger as the default start page for API hosted on the Azure web app?

I created an Asp.Net Core 2.x Web API and configured Swagger on it, below is the code added in Configure method under Startup.cs file, for full swagger configuration, check here //Add swagger configuration app.UseSwagger(); app.UseSwaggerUI(c => {     c.SwaggerEndpoint( "../swagger/v1/swagger.json" , "Test API V1" ); }); On my local machine when I run the API it is automatically redirected to the Swagger page. However, when I hosted this API as an Azure web app it is not redirecting directly to the Swagger and to access the swagger, I had to append /swagger in the URL, for example, https://testapi.azurewebsites.net/swagger/ Solution: Set RoutePrefix to string.Empty under app.UseSwaggerUI like below: app.UseSwaggerUI(c => {     c.SwaggerEndpoint( "../swagger/v1/swagger.json" , "Test API V1" );      c.RoutePrefix = string .Empty; // Set Swagger UI at apps root }); And that’s it, now when you brows