Oct 08 2024
Sponsored
• Join Postman CTO, Ankit Sobti, and Head of Customer Experience and Success, Kristine Chin, at this webinar which delivers the information you need to maximize the success of your API products, reduce friction to collaboration, and to provide a world-class experience for your developers, partners, and customers. Join here.
• Learn effective testing strategies, explore powerful new features, and automate your API workflows effortlessly. Avoid common pitfalls and elevate your API development with API Testing and Development with Postman by Dave Westerveld.
Many thanks to the sponsors who make it possible for this newsletter to be free for readers. Become a sponsor.
In software engineering, the Singleton pattern stands out as a widely recognized pattern. The core idea of a Singleton is that it is a class designed to only create one instance of itself, and it typically provides an easy way to access that instance. Generally, Singletons are created without allowing any parameters for the instance creation. This is to prevent complications that might arise from attempting to create a second instance with different parameters. If a scenario requires accessing the same instance for every request with identical parameters, the factory pattern is a more suitable choice. This discussion is focused solely on cases where no parameters are needed for creating the singleton. A common characteristic of Singletons is their lazy creation, meaning the instance is not generated until it is first required. Let's see how to implement it properly.
Under normal circumstances, this would be a common piece of code you would see in an application.
public sealed class Singleton{ private static Singleton instance = null; private Singleton() { } public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } }}
This isn't thread safe when used with multiple threads. What can happen is two threads might check if the instance is null at the same time and both find it to be true. As a result, they each create an instance, which goes against the rule of having only one instance in the singleton pattern. Also, it's possible that an instance is already made before this check happens, but other threads might not see this new instance right away unless certain steps are taken to make sure they do. How to make it thread safe?
This is the well-known approach to implement it. Here's how it works:
public sealed class Singleton{ private static Singleton instance = null; private static readonly object padlock = new object(); Singleton() { } public static Singleton Instance { get { lock (padlock) { if (instance == null) { instance = new Singleton(); } return instance; } } }}
The downside is that this method can slow things down because it requires locking every time the instance is needed. Okay, is it necessary to lock it every time? Nope. Let's look deeper.
First Check: When accessing the instance, the first check is to see if the instance is null. If it's not null, it returns the existing instance. This first check avoids the locking overhead in most calls after the instance is initialized.
Locking: If the instance is null, a lock is obtained. Second Check: Once inside the lock, a second check on the instance is performed. This is because another thread might have initialized the instance between the first check and obtaining the lock. If the instance is still null after this second check, it is created.
public sealed class Singleton{ private static Singleton instance = null; private static readonly object padlock = new object(); Singleton() { } public static Singleton Instance { get { if (instance == null) { lock (padlock) { if (instance == null) { instance = new Singleton(); } } } return instance; } }}
So we found the best solution?
Not really. This one is really tricky one, and it can cause problems if not used properly.
So what is the best solution?
In my opinion, there is no "Best" solution. It totally depends on a case by case basis. I like and suggest using Lazy
Here's how you can implement a Singleton pattern using Lazy
• Lazy Initialization: The Lazy
public class Singleton{ private static readonly Lazy<Singleton> instance = new Lazy<Singleton>(() => new Singleton()); private Singleton() { } public static Singleton Instance => instance.Value;}
The key benefits of using Lazy
This approach is recommended in modern C# development over manually implementing double-check locking, as it leverages the capabilities of the .NET Framework for handling lazy initialization in a thread-safe manner.
In today's newsletter issue, we went through some of the most common implementations of the Singleton pattern. We have:
That's all from me today. _
P.S. If you want to see some more examples of this pattern or 9 more patterns I explained in my ebook "Design Patterns Simplified", you can check out it here.
800+ enigneers already read it.
Want to enforce clean code automatically? My Pragmatic .NET Code Rules course shows you how to set up analyzers, CI quality gates, and architecture tests - a production-ready system that keeps your codebase clean without manual reviews. Or grab the free Starter Kit to try it out.
Stop arguing about code style. In this course you get a production-proven setup with analyzers, CI quality gates, and architecture tests — the exact system I use in real projects. Join here.
Not sure yet? Grab the free Starter Kit — a drop-in setup with the essentials from Module 01.
Design Patterns that Deliver — Solve real problems with 5 battle-tested patterns (Builder, Decorator, Strategy, Adapter, Mediator) using practical, real-world examples. Trusted by 650+ developers.
Just getting started? Design Patterns Simplified covers 10 essential patterns in a beginner-friendly, 30-page guide for just $9.95.
Every Monday morning, I share 1 actionable tip on C#, .NET & Architecture that you can use right away. Join here.
Join 20,000+ subscribers who mass-improve their .NET skills with actionable tips on C#, Architecture & Best Practices.
Subscribe to the TheCodeMan.net and be among the 20,000+ subscribers gaining practical tips and resources to enhance your .NET expertise.