Click here to Skip to main content
14,664,281 members
Articles » Languages » C# » Generics
Tip/Trick
Posted 25 Sep 2020

Tagged as

Stats

2.3K views
2 bookmarked

Thread Safe Generic Singleton

Rate this:
1.73 (7 votes)
Please Sign up or sign in to vote.
1.73 (7 votes)
25 Sep 2020CPOL
Simple and thread safe implementation of generic singleton
Generic singleton class without lock and thread safe - it describes everything you need :)

Introduction

Like always, I would like to bring some light in the dark tunnel to those who are trying to implement singleton classes. Most searches bring up code which work in some cases and give a lot of problems in large scaled/multithreaded applications.

Many of them use lock, even double locks :) (I know more locks giving you more security :) - just a small joke).
Also, you can find a way to make your class as singleton, but very deep in the internet, you can find a solution which I have been using since at least 15 years as far as I can remember.

SingletonT<TInstance>

As you can see, the code is simple and self describing:

public class SingletonT<TInstance> where TInstance : new()
{
    private static readonly TInstance _instance = new TInstance();

    public static TInstance Instance => _instance;
}

Or if you would like to add some additional actions based on interface, e.g., like this:

public interface IAsyncComponent
{
    bool IsAlive { get; }

    void Start();
    void Stop();
}

SingletonT with additional code based on the interface:

public class SingletonT<TInstance> where TInstance : new()
{
    private static readonly TInstance _instance = new TInstance();

    public static TInstance Instance
    {
        get
        {
            if (_instance is IAsyncComponent asyncComponent)
            {
                if (!asyncComponent.IsAlive)
                    asyncComponent.Start();
            }
            return _instance;
        }
    }
}

This is an example of how you can increase functionality of the SingletonT. And as you can see, you can create a singleton of every object which has default constructor without parameters. And in addition, if this class will have interface IAsyncComponent, it will start automatically. I know you would not always like to start it :) -> THIS IS ONLY AN EXAMPLE !

It is not needed to add Lazy<> part because this code is automatically compiled to IL code with Lazy<> part.
Part with private static variable will be created only during the first usage. If you will not use it in your code, you will not have any impact on memory.

Also, it is a free lock because it is guaranteed by C# that initialization of the class will perform only one time even if you will call from many threads (means call constructor only one time). This give us guarantee that private variable is safe in multithreading without any lock :).

Now you have the freedom to create SingletonT from any class which has a default empty constructor without changing anything in your class.

Why and When using SingletonT<> ????

You can use SingletonT<> wherever you would like to use static class from the class which inherits from another class and you would like to have global static class with interfaces.
As you know, static classes cannot have any base class and interfaces because static classes are sealed.

Using the Code

Using of this pattern is as simple as this class is created:

var someVariableName = SingletonT<YourClass>.Instance;

Now you can ask: hey, I would like to pass some parameters to the constructor !!!
You can do this by first creating your class with parameters:

public class YourClassParameters
{
    string Parameter1 = "Test1";
    Int64  Parameter2 = 3245;
}

And use it in constructor of "YourClass" as SingletonT<YourClassParameters>.Instance and use it in your constructor as:

public class YourClass
{
    private string _path;
    private Int64  _maxFiles;

    public YourClass()
    {
        _path = SingletonT<YourClassParameters>.Instance.Parameter1;
        _maxFiles = SingletonT<YourClassParameters>.Instance.Parameter2;
    }
}

or in a simple way:

public class YourClass 
{
    private YourClassParameters _startupParameters = SingletonT<YourClassParameters>.Instance;
    private _maxFiles;

    public YourClass()
    {
        Initialize(_startupParameters.Parameter1, _startupParameters2);
    } 
}

Or just create static class from YourClassParameters :) It will also work well.

WARNING: But if you trying to follow the path that your global static class constructor has to be called with parameters means that your design is not really proper and you have to start thinking where your problem lies. :)
But also sometimes, it is nice to have global starting parameters to set them up in one place without going around the code. There is always darkness in this area. :)

Conclusion

I hope I have given you a small light in the dark tunnel of programming.

History

  • 25th September, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

TymekMM
Netherlands Netherlands
No Biography provided

Comments and Discussions

 
QuestionGood, but not thread-safe Pin
Chris Copeland27-Sep-20 23:05
professionalChris Copeland27-Sep-20 23:05 
AnswerRe: Good, but not thread-safe Pin
TymekMM7-Oct-20 3:22
MemberTymekMM7-Oct-20 3:22 
GeneralRe: Good, but not thread-safe Pin
Chris Copeland7-Oct-20 4:44
professionalChris Copeland7-Oct-20 4:44 
GeneralRe: Good, but not thread-safe Pin
TymekMM7-Oct-20 9:51
MemberTymekMM7-Oct-20 9:51 
GeneralRe: Good, but not thread-safe Pin
Chris Copeland7-Oct-20 23:12
professionalChris Copeland7-Oct-20 23:12 
QuestionMisleading Pin
Dmitry Mukalov26-Sep-20 1:52
MemberDmitry Mukalov26-Sep-20 1:52 
AnswerRe: Misleading Pin
TymekMM26-Sep-20 3:27
MemberTymekMM26-Sep-20 3:27 
GeneralRe: Misleading Pin
Dmitry Mukalov26-Sep-20 3:49
MemberDmitry Mukalov26-Sep-20 3:49 
GeneralRe: Misleading Pin
TymekMM26-Sep-20 7:32
MemberTymekMM26-Sep-20 7:32 
GeneralRe: Misleading Pin
Dmitry Mukalov26-Sep-20 23:06
MemberDmitry Mukalov26-Sep-20 23:06 
GeneralRe: Misleading Pin
TymekMM27-Sep-20 4:49
MemberTymekMM27-Sep-20 4:49 
GeneralRe: Misleading Pin
Dmitry Mukalov27-Sep-20 8:19
MemberDmitry Mukalov27-Sep-20 8:19 
GeneralRe: Misleading Pin
TymekMM27-Sep-20 11:17
MemberTymekMM27-Sep-20 11:17 
GeneralRe: Misleading Pin
OriginalGriff27-Sep-20 11:25
mveOriginalGriff27-Sep-20 11:25 
GeneralRe: Misleading Pin
OriginalGriff27-Sep-20 11:26
mveOriginalGriff27-Sep-20 11:26 
QuestionAnti Pattern and Lazy? Pin
GerVenson26-Sep-20 1:04
professionalGerVenson26-Sep-20 1:04 
AnswerRe: Anti Pattern and Lazy? Pin
TymekMM26-Sep-20 1:24
MemberTymekMM26-Sep-20 1:24 
GeneralRe: Anti Pattern and Lazy? Pin
GerVenson27-Sep-20 22:19
professionalGerVenson27-Sep-20 22:19 
GeneralThoughts Pin
PIEBALDconsult25-Sep-20 14:58
professionalPIEBALDconsult25-Sep-20 14:58 
GeneralRe: Thoughts Pin
TymekMM26-Sep-20 1:17
MemberTymekMM26-Sep-20 1:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.