How to implement a Singleton design pattern in C#?

The Singleton design pattern belongs to the Creational type pattern. It ensures that only one instance of a particular class is created throughout the application lifecycle. This single instance coordinates actions across the application and provides global access to shared resources.

The Singleton pattern is useful when you need exactly one instance of a class, such as for logging, caching, thread pools, or configuration settings.

Implementation Guidelines

  • Declare all constructors as private to prevent external instantiation.

  • Provide a static property or method that returns the single instance.

  • Store the instance in a static field to ensure single creation.

  • Use sealed keyword to prevent inheritance.

Singleton Pattern Structure Singleton - instance: Singleton - Singleton() + GetInstance(): Singleton + PrintDetails(string): void Only one instance can exist

Syntax

Following is the basic syntax for implementing a Singleton pattern −

public sealed class Singleton {
   private static Singleton instance = null;
   
   private Singleton() {
      // Private constructor
   }
   
   public static Singleton GetInstance {
      get {
         if (instance == null)
            instance = new Singleton();
         return instance;
      }
   }
}

Basic Singleton Implementation

Here is a simple implementation of the Singleton pattern −

using System;

public sealed class Singleton {
   private static int counter = 0;
   private static Singleton instance = null;
   
   public static Singleton GetInstance {
      get {
         if (instance == null)
            instance = new Singleton();
         return instance;
      }
   }
   
   private Singleton() {
      counter++;
      Console.WriteLine("Counter Value " + counter.ToString());
   }
   
   public void PrintDetails(string message) {
      Console.WriteLine(message);
   }
}

class Program {
   static void Main() {
      Singleton fromFacebook = Singleton.GetInstance;
      fromFacebook.PrintDetails("From Facebook");
      
      Singleton fromTwitter = Singleton.GetInstance;
      fromTwitter.PrintDetails("From Twitter");
      
      Console.WriteLine("Are both instances the same? " + 
                       ReferenceEquals(fromFacebook, fromTwitter));
   }
}

The output of the above code is −

Counter Value 1
From Facebook
From Twitter
Are both instances the same? True

Thread-Safe Singleton Implementation

The basic implementation is not thread-safe. Here's a thread-safe version using lock

using System;

public sealed class ThreadSafeSingleton {
   private static ThreadSafeSingleton instance = null;
   private static readonly object lockObject = new object();
   
   public static ThreadSafeSingleton GetInstance {
      get {
         lock (lockObject) {
            if (instance == null)
               instance = new ThreadSafeSingleton();
            return instance;
         }
      }
   }
   
   private ThreadSafeSingleton() {
      Console.WriteLine("Thread-safe Singleton instance created");
   }
   
   public void DoWork() {
      Console.WriteLine("Performing work in thread-safe singleton");
   }
}

class Program {
   static void Main() {
      ThreadSafeSingleton instance1 = ThreadSafeSingleton.GetInstance;
      instance1.DoWork();
      
      ThreadSafeSingleton instance2 = ThreadSafeSingleton.GetInstance;
      instance2.DoWork();
      
      Console.WriteLine("Same instance? " + ReferenceEquals(instance1, instance2));
   }
}

The output of the above code is −

Thread-safe Singleton instance created
Performing work in thread-safe singleton
Performing work in thread-safe singleton
Same instance? True

Lazy Initialization Singleton

C# provides Lazy<T> for thread-safe lazy initialization −

using System;

public sealed class LazySingleton {
   private static readonly Lazy<LazySingleton> lazy = 
      new Lazy<LazySingleton>(() => new LazySingleton());
   
   public static LazySingleton Instance {
      get { return lazy.Value; }
   }
   
   private LazySingleton() {
      Console.WriteLine("Lazy Singleton instance created");
   }
   
   public void DisplayMessage() {
      Console.WriteLine("Lazy Singleton is working!");
   }
}

class Program {
   static void Main() {
      Console.WriteLine("Before accessing singleton");
      
      LazySingleton instance1 = LazySingleton.Instance;
      instance1.DisplayMessage();
      
      LazySingleton instance2 = LazySingleton.Instance;
      instance2.DisplayMessage();
      
      Console.WriteLine("Same instance? " + ReferenceEquals(instance1, instance2));
   }
}

The output of the above code is −

Before accessing singleton
Lazy Singleton instance created
Lazy Singleton is working!
Lazy Singleton is working!
Same instance? True

Comparison of Singleton Implementations

Implementation Thread Safety Performance Complexity
Basic Singleton Not thread-safe Fast Simple
Lock-based Singleton Thread-safe Slower due to locking Moderate
Lazy<T> Singleton Thread-safe Good performance Simple

Common Use Cases

  • Database connections − Managing a single connection pool

  • Configuration settings − Loading application settings once

  • Logging − Single logger instance across the application

  • Caching − Shared cache accessible throughout the application

Conclusion

The Singleton design pattern ensures only one instance of a class exists throughout the application. Use the Lazy<T> approach for thread-safe, high-performance singleton implementation. The pattern is ideal for managing shared resources like database connections, configuration settings, and logging systems.

Updated on: 2026-03-17T07:04:36+05:30

614 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements