What is a singleton in C?
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Introduction
A singleton is a design pattern that ensures a class has exactly one shared instance and exposes a global way to reach it. In C#, the pattern is usually implemented with a private constructor and a static property or field. The mechanics are simple, but the design tradeoff matters more than the syntax.
The Core Shape of a Singleton in C#
The basic idea is to block direct construction from outside the class and keep one shared instance inside the type itself.
Usage:
This works because the CLR initializes static fields only once per application domain. The sealed keyword is also helpful because it prevents subclassing, which could otherwise complicate the "exactly one instance" rule.
Lazy Initialization and Thread Safety
Sometimes you do not want to create the singleton until it is first needed. In modern C#, Lazy<T> is the cleanest way to do that safely.
This version is both lazy and thread-safe without custom locking code. That is usually better than hand-written double-checked locking unless you have a very specific reason to manage the synchronization yourself.
When a Singleton Can Make Sense
Singletons are sometimes reasonable when the application truly has one shared coordinator, such as:
- a configuration cache
- a process-wide metrics collector
- a lightweight logger wrapper
- a shared registry with one global view
The pattern is most defensible when the object represents a real single concept in the process and when global access is actually helpful rather than just convenient.
Why Singletons Are Often Overused
The pattern is popular because it is easy to write, but that does not mean it is always a good design. A singleton is still global mutable state if the instance can change internally. That makes code harder to test, harder to reason about, and more tightly coupled.
For example, this class compiles fine but is painful in tests because every test shares the same underlying state:
If one test increments the counter and another expects zero, they now interfere unless the shared state is carefully reset.
Prefer Dependency Injection When You Can
In modern C# applications, especially ASP.NET Core, dependency injection often gives the same "one shared service" behavior with better testability. A service can be registered as a singleton in the container without hard-coding global access into the type itself.
That still creates one shared instance for the application, but consumers receive it through constructor injection. This keeps dependencies explicit and makes mocking or replacement easier in tests.
Common Pitfalls
One common mistake is using a singleton just to avoid passing dependencies around. That usually hides coupling instead of reducing it.
Another mistake is forgetting that shared mutable state is a concurrency concern. A singleton does not become thread-safe just because there is only one instance.
Developers also sometimes write manual locking code when static readonly initialization or Lazy<T> would be simpler and safer.
Finally, a singleton can become a dumping ground for unrelated behavior. Once a type is globally accessible, teams often keep adding responsibilities until it turns into an unmaintainable god object.
Summary
- A singleton ensures one shared instance of a class and exposes a global access point.
- In C#, private constructors plus static members are the standard implementation pattern.
- '
Lazy<T>is a clean way to get lazy, thread-safe initialization.' - Singletons are easy to write but can introduce hidden coupling and shared-state problems.
- Prefer dependency injection when you want one shared service without hard-coded global access.
Related reading
- What is Bulkhead Pattern used by Hystrix?
- What is lazy initialization and why is it useful?
- What is PECS (Producer Extends Consumer Super)?
- What is the best way of implementing a singleton in Python?
- What is a .snk for?
- What is a 'workspace' in Visual Studio Code?
- What is the difference between ? and Object in Java generics?
- What is the difference between Builder Design pattern and Factory Design pattern?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.