Singleton Pattern in C# – One and Only
The Singleton Pattern ensures a class has only one instance and provides a global access point to it. It's useful when exactly one object is needed to coordinate actions across a system.
Real-Life Analogy: Office Printer
Imagine an office with one shared printer. All employees use the same printer — there isn't a separate printer for each person. If someone wants to print something, they go through the shared printer queue.
The printer is created once and accessed by everyone. That's exactly how Singleton works — one instance used across the entire system.

Benefits of Singleton
Singleton ensures consistency and saves resources. Instead of creating multiple instances of a resource-heavy class, you share one — saving memory and ensuring predictable behaviour.
It simplifies access to global services like configuration or logging.
- Only one instance created in memory
- Shared state across multiple places
- Useful for logging, configuration, or resource managers
When Should You Use It?
Singleton is useful when you want a single point of access to a shared resource — and when having more than one instance would break things. It is commonly used for system-wide services that manage shared data or settings.
- Database connections
- Logging services
- Configuration or environment readers
When Not to Use It: Avoid it when multiple instances are needed, or when it introduces unwanted shared state in multi-threaded apps.
What to Implement
To implement a Singleton in C#, you typically need:
- A private constructor to prevent external instantiation
- A static field to hold the single instance
- A public static property to return the instance
- Thread safety to ensure only one instance is created even in multithreaded scenarios
How It Works in C#
public class Printer
{
private static Printer instance;
private static readonly object lockObj = new();
private Printer() { }
public static Printer Instance
{
get
{
lock (lockObj)
{
return instance ??= new Printer();
}
}
}
public void Print(string document)
{
Console.WriteLine($"Printing: {document}");
}
}
Usage:
Printer.Instance.Print("Invoice.pdf");
Lazy Singleton Explained
The above approach works well, but can be simplified using C#'s built-in Lazy<T>
class, which ensures the object is created only when it's first used — and handles thread safety for you.
This is called lazy initialisation and is the recommended way to write singletons in modern C#.
public sealed class LazyPrinter
{
private static readonly Lazy<LazyPrinter> lazy =
new(() => new LazyPrinter());
public static LazyPrinter Instance => lazy.Value;
private LazyPrinter() { }
public void Print(string message)
{
Console.WriteLine($"[Lazy] Printing: {message}");
}
}
Usage:
LazyPrinter.Instance.Print("Monthly Report");
Final Thoughts
The Singleton Pattern is ideal when one and only one object is needed for the job. It keeps your app simple when central coordination is required — just like one printer for the whole office.
While Singleton can be useful, it should be applied with care — especially in multithreaded or test-heavy environments where shared state can cause issues.