Singleton Pattern comes under creational design patterns category, this pattern lets you define a class that has only one instance, while providing a global access to this created instance. As singleton is a class designed to only ever have one instance.
Singleton instance example
- Access to file system.
- Access to shared network resource
- Expensive one-time configuration
Singleton Structure
- Singleton instance which is private
- Singleton public method/function to access singleton object.
- Private constructor
- Other methods and properties
Singleton Features
- At any time, only 0 or 1 instance of Singleton class exists in the application.
- Singleton classes are created without parameters.
- Assume lazy instantiation as the default.
- A single, private, parameter-less constructor and class should be sealed.
- A private static field holds the only reference to the instance.
- A public static method provides access to this field.
Singleton Implementation in C#
- Naïve Singleton - Not thread safe but provide performance
- Thread Safe Singleton - Thread safe will slow down performance. Double check thread safe singleton pattern used to optimize the performance.
- Leveraging Static Constructors - C# static constructors only run once per app domain. Are called when any static member of a type is referenced. Make sure you use an explicit static constructor to avoid issue with c# compiler and before field init. (https://csharpindepth.com/articles/BeforeFieldInit)
- Lazy<T> - Lazy<T> was introduced in .Net 4, provides built-in support for lazy initialization. Specify a means of creating Type.
Singleton Pattern is also consider as Antipattern.
- Difficult to test due to shared state.
- Doesn't follow Separation of Concerns.
- Doesn't follow single responsibility
- Doesn't follow DRY
- Better alternative exist.
Singletons vs. Static Classes
Singleton
- Can implement interfaces
- Can be passed as an argument
- Can be assigned to variables
- Support polymorphism
- Can have state
- Can be serialized
Static Classes
- No interfaces
- Cannot be passed as arguments
- Cannot be assigned
- Purely procedural
- Can only access global state
- No support for serialization
Singletons Behavior Using Containers (IoC)
- You can use dependency injection tool/library to inject dependency.
- Container manages instance lifetime
- .Net core has inbuilt support for dependency injection using service provide.