Basics of Lazy Initialization
Lazy initialization is a design pattern that delays the creation of an object until it is actually needed. This is useful for:
- Reducing startup time
- Saving memory and CPU resources
- Ensuring objects are only created if used
Singleton Pattern
The Singleton pattern ensures a class has only one instance and provides a global point of access to it. Lazy<Singleton>
is a common way to implement this in C#.
public sealed class Singleton {
private static readonly Lazy<Singleton> _lazy =
new(() => new Singleton());
public static Singleton Instance => _lazy.Value;
private Singleton() { }
public void DoWork() => Console.WriteLine("Singleton is working!");
}
The Lazy<T> Class
Lazy<T>
is a generic class in .NET that wraps a value of type T
and ensures it is initialized only once when .Value
is accessed for the first time.
private static readonly Lazy<Singleton> _lazy =
new(() => new Singleton());
var instance = Singleton.Instance; // Singleton created here
Lambda Expression Explained
The () => new Singleton()
syntax is a lambda expression. It defines a factory method for creating the Singleton instance. It is:
- Not executed immediately
- Executed only the first time
.Value
is accessed - Ensures the object is only created once
Thread Safety
Lazy<T>
ensures that only one thread initializes the value, even in multi-threaded environments, using a double-check lock pattern internally.
When to Use Lazy Initialization
- The object is resource-intensive to create
- Initialization may never be needed
- Thread-safe single instance is required
Comparison with Other Languages
- Java: Use synchronized getter, AtomicReference, or static inner class (Bill Pugh Singleton)
- Python: Use closures, decorators, or module-level caching
- C++: Use
std::call_once
with static local variable or smart pointer