What is a “Singleton Class” in C#?
A “Singleton” is an object-oriented programming concept in C#. It is a design pattern that restricts creating classes in more than one instance. So, it is a design pattern of classes. This ensures that in every part of the C# program, there will be only one class in action to receive any changes and updates from other classes. It is a global point of access for every other class to only possible one instance of a class, a singleton.
If we were to create a different instance of a class each time, then there would be partially modified many instances all over the code, one instance would adopt one change; and one would adopt the other, etc. so the program would work with so many unexpected behaviors. When there is a need to use the class again, if the class is a singleton, you use the same instance that you have already created before.
Singleton is like a loved one where you can not create or find someone like him/her. You have only one significant other(a singleton/ one instance) to do many activities(many different classes) on valentines day. Moreover, a singleton class makes sure that you do not cheat on her/him, by putting validation checks and not allowing the creation of other significant others(other class instances) by having a private constructor(a private agent/detective of your significant other that gets intel for her/him).
How to create a Singleton Class?
The creation of a singleton relies on the use of modifier static. In a singleton class, at least 2 static members are needed: A static field, a static method, or a static property.
public class SingletonClass
{
//static field with the data type of its own class
private static SingletonClass _instance;
private SingletonClass()
{
//empty right now
}
//static property
public static SingletonClass Instance
{
get
{
//create a singleton, if not created already
if (_instance == null)
{
//instancing happens
_instance = new SingletonClass();
}
return _instance;
}
}
}
The static property is responsible for returning a single instance of the class it resides in.
The static property is also responsible for creating the instance of the singleton class if it hasn’t been created already.
public class SingletonClass
{
//static field with the data type of its own class
private static SingletonClass _instance
private SingletonClass()
{
//empty right now
}
//traditional static method to get the singleton instance
public static SingletonClass GetInstance()
{
//create a singleton, if not created already
if (_instance == null)
{
//instancing happens
_instance = new SingletonClass();
}
return _instance;
}
}
A singleton class’ static elements continue to exist until the application is closed.
Other than static members, there should be a member private constructor as well. It is there to prevent other classes/external codes from creating other instances of the SingletonClass
.
Depending on whether putting validations checks and logic or not inside getters and setters of properties, there could be a private static field with the type of its own class, which is SingletonClass
here, above the property too.
In the Singleton design pattern, it is common practice to use private access modifiers for fields in the Singleton class, because, in general, there are validations taking place.
The public static Instance
property provides a way for other parts of the program or other classes to access the single instance of the class, and the if (instance == null)
check ensures that the instance is only created the first time the instance is accessed. If the instance of the class has already been created which means is not null; then the property returns a single already existing instance of the SingletonClass
.
To elaborate more clearly, when we call SingletonClass.Instance
, the get
method of the static property checks if the static field instance is null. If it is, it creates a new instance of the SingletonClass
and assigns it to the instance
. If it is not null, it simply returns the existing instance.
This ensures that there is only ever one instance of SingletonClass
in the entire program. This is useful in situations where you need to ensure that there is only one instance of a particular object in the entire program, such as a configuration object or a database connection object.
Here is an example of using & calling a singleton class in another class:
public class OtherClass
{
public void SomeMethod()
{
SingletonClass instance = SingletonClass.Instance;
// Use the instance of SingletonClass here
}
}
As I mentioned above, the Instance property of the SingletonClass
is a static member so we access it from OtherClass
as we access any other static member: By “invoking”. When we access it, necessary validation checks are done inside the getter of the static property of SingletonClass
and then the existing instance is returned, then passed into the SingletonClass instance
of SomeMethod()
of OtherClass
In summary, when a static member such as a field, method, or property is declared in a class, it becomes associated with the type of the class and is created when the class is loaded into memory. The static member persists throughout the lifetime of the application or until the class is unloaded from memory.
In the case of a singleton class, the static elements such as static fields, methods, and properties are linked to the single instance of the class that is created and stored in a private static field. As the singleton class only allows a single instance to be created throughout the lifetime of the application, its static elements will continue to exist until the application terminates.
When to use singleton and when not to?
Use singleton:
In C#, the Singleton pattern can be useful for scenarios such as configuration settings, logging, caching, and database connections.
- If an application needs to read configuration settings from a file or database that is accessed by multiple parts of the application, the Singleton pattern can be used to create a single instance of the configuration class that can be accessed by all parts of the application. So, a configuration class can be implemented as a singleton to provide a single point of access to the configuration settings for the application. — Configuration Settings
- A logging class can be implemented as a singleton to ensure that there is only one instance of the class logging messages throughout the application. To log information in an application, a singleton logger class can be created that writes log data to a file or database. All parts of the application can use this logger instance to write log data. — Logging
- If an application needs to cache data in memory to improve performance, the Singleton pattern can be used to create a single instance of a caching class that can be accessed by all parts of the application. — Catching
- If an application needs to use a database, a singleton database class can be created to manage the database connection. All parts of the application can use this instance to access the database. — Database Connection
Do not use singleton:
- If a class is tightly coupled to the Singleton class, testing the class in isolation can be difficult since the Singleton class cannot be easily replaced with a test double, which can make it harder to change and maintain the code over time. Also, they can make testing more difficult since they are designed to have only one instance. — Testability
- If an application requires multiple instances of a class, the Singleton pattern may not be appropriate since it limits the application to a single instance of the class. This can cause problems if the application needs to scale to handle more users or data. — Parallelism
- If an application uses dependency injection to manage its dependencies, the Singleton pattern may not be appropriate. Dependency injection provides a way to create and manage instances of classes, making the Singleton pattern unnecessary. — Dependency Injection
Additional Reasons not to use Singletons:
- When there are no stateful operations: If a class does not maintain any state and just provides utility functions or a collection of constants, then it’s not necessary to use the Singleton pattern. In such cases, static methods or functions can be used instead.
- When multiple instances are required: If a class needs to create multiple instances with different configurations, then the Singleton pattern may not be the best fit. In such cases, a factory pattern or dependency injection can be used to create and manage multiple instances.
- When it violates the Single Responsibility Principle (SRP): If a class has multiple responsibilities and does more than one thing, then it’s not recommended to use the Singleton pattern. The reason is, it can lead to tight coupling and make the code harder to maintain and test.
- When it creates unnecessary complexity: If a class does not require a global point of access and is not part of a larger architecture, then using the Singleton pattern can create unnecessary complexity and make the code harder to understand.
Important!
Since a singleton class is not a static class, a singleton class can have non-static members, unlike a static class.
Single Object/Instance
public sealed class MySingletonClass
{
private static readonly MySingletonClass _instance = new MySingletonClass();
private MySingletonClass()
{
// private constructor to prevent external instantiation
}
public static MySingletonClass Instance
{
get
{
return _instance;
}
}
// other class members and methods
}
private static readonly MySingletonClass instance = new MySingletonClass()
what this code does above line is often called creating a “Single Object” or “Single Instance” because the field stores the new single instance/object of the MySingleton
class. Single Objects are found in the singleton design pattern and are generally marked with all 3 "private static readonly
" access modifiers to make sure that the singleton class has only one instance.
It should be stated that private static readonly MySingletonClass instance = new MySingletonClass()
is a field as well. It is a field that holds one single instance of the MySingletonClass
.
Only Getter? No Setter inside a property of a Singleton class? Why put readonly then?
private static readonly MySingleton _instance = new MySingleton();
If there is no setter method for a field in a singleton class, it is still strictly necessary to mark the field as readonly
. Furthermore doing this can help communicate to other developers that the field should not be modified, even within the class itself. It can also help prevent accidental modifications to the field if someone else were to modify the class in the future.
Additionally, marking the field as readonly
can help with performance in some cases, as the compiler can optimize code that accesses readonly
fields in certain ways.
We know that if a property in a class does not have a setter method, the property becomes readonly, and it will be impossible to set the field by using property from either inside(from the constructor) of the class or outside of the class. But if we do not put readonly to the field, it is still possible to create a new instance of the singleton class by assigning it = new Singleton()
like this: SingletonClass._instance = new SingletonClass()
. This would create another instance of SingletonClass
We put a readonly
access modifier to the field above the property to ensure that the field will never be set to a new value neither from inside of the class, nor from the constructor, a traditional setter method, or even an accidentally put setter method of its property nor from outside of the class.
If the field is not marked as readonly
, adding a setter method, whether as a property’s setter or a traditional setter method, inside a singleton class would allow modification of its single object/instance/field, potentially resulting in the creation of a new instance of the singleton class via the assignment of = new SingletonClass()
outside of the class. This defeats the purpose of creating a singleton class in the first place, which is to ensure only one instance of the class exists throughout the lifetime of the application."
public class SingletonClass
{
private readonly static SingletonClass _greetings;
public static SingletonClass Greetings
{
get { return _greetings; }
set { _greetings = value; }
}
}
static void Main(string[] args)
{
//Singleton Pattern HAS BEEN PRESERVED! NO INSTANCE WAS CREATED!
SingletonClass.Greetings = new SingletonClass(); //ERROR!!
//no SET has been done.
}
Not putting the readonly
modifier and having a setter method in a singleton class would allow both external code and internal code to change the value of the singleton object's fields, potentially creating a new state for the singleton object. This again would break the intended behavior of the singleton pattern, which is to have only one instance of the class throughout the lifetime of the application.
Regardless of whether the application employs multithreading, making all fields in a singleton class readonly
is generally a good practice. It is true that multithreading increases the possibility of unintentional or deliberate changes to a singleton object’s state, so putting readonly
helps to maintain the integrity of the singleton pattern by making sure the singleton object stays in a consistent state and prevents unintentional or deliberate modifications to it.
Note: Properties can not be readonly, fields can. Properties that do not have a setter method are readonly for their property, but their field can be accessed if it is not marked as readonly
Important 1!
There would be no readonly
modifier on Singleton Class’s field, if the singleton class has a validation check inside of their class like “if the field is not null return same instance, if the field is null, then create the instance”. Because readonly
modifier will make it impossible to assign new
and create a new instance, as shown below:
Important 2!
If you are converting a static class into a singleton class and want to use a singleton pattern, the static members of the static class that you are using inside of any other classes must be changed to non-static members as well, because, now you are calling them by the singleton classes instance(always the same instance).
Important 3!
Creating too many singleton classes would result in a Stack Overflow error. To prevent this, you should prefer Lazy Loading instead of Eager Loading. This way you will be able to create the singleton instance only when it is first requested and needed, rather than being created eagerly at the application startup.
Lazy Loading Singleton Class vs Eager Loading Singleton
Lazy Loading Singleton Class:
public sealed class MySingleton
{
private static readonly Lazy<MySingleton> lazyInstance =
new Lazy<MySingleton>(() => new MySingleton());
public static MySingleton Instance
{
get { return lazyInstance.Value; }
}
private MySingleton()
{
// Constructor logic here
}
// Other methods and properties here
}
Note: This type of Lazy<> Loading above without null validation can cause “Object reference not set to an instance of an object” error. Try preferring the code below with validation check,(notice that the field here is not readonly
):
public sealed class MySingleton
{
private static Lazy<MySingleton> _lazyInstance;
public static MySingleton Instance
{
get
{
if (Instance == null)
{
_lazyInstance = new Lazy<MySingleton>(() => new MySingleton());
}
return _lazyInstance.Value;
}
}
private MySingleton()
{
// Constructor
}
}
Eager Loading Singleton Class
public sealed class MySingleton
{
private static readonly MySingleton instance = new MySingleton();
public static MySingleton Instance
{
get { return instance; }
}
private MySingleton()
{
// Constructor logic here
}
// Other methods and properties here
}
public sealed class MySingleton
{
private static readonly MySingleton _instance = new MySingleton();
public static MySingleton Instance
{
get
{
if(_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
}
private MySingleton()
{
// Constructor logic here
}
// Other methods and properties here
}
Important!: Singleton Design Pattern Violates SRP of SOLID Principles
The SRP states that a class should have only one reason to change, meaning it should have only one responsibility or job. This helps to improve maintainability and reduces the impact of changes on other parts of the code.
On the other hand, the Singleton Design Pattern is a creational pattern that ensures that only one instance of a class can be created and provides a global point of access to that instance. So, there is no single responsibility when implementing singleton design patterns.
Real Life Applications of Singleton Pattern
- Exception/Information logging
- Connection pool management
- File management
- Device management such as printer spooling
- Application Configuration Management
- Cache management
- Session-based shopping cart
A Clap or a Comment is much appreciated! Thank you for your time!
Resources For Further Study:
Design Patterns: Singleton | Microsoft Learn
My other relevant stories:
Explaining Interfaces in C# OOP
Non-Generic Collections in C# OOP: Part 1
Dynamic Memory Allocation VS Static Memory Allocation Common
Collection Interfaces in C#: A Quick Summary
Difference between “Field” and “Property” in C# OOP
Static Class & Singleton Class in C# OOP
Default Access Modifiers in C# OOP