Singleton – A class of which only a single instance can exist.
From Design Pattern – Creational Patterns
Structure
Applicability
Using the Singleton pattern is when all clients available to call its class and only a single instance available in the program. For example, a single object share with other parts of the program to use.
Using the Singleton pattern is when the program or the project needs stricter to controller the global variable.
Some real-time scenarios about the Singleton pattern that shows below:
Pros and Cons
PRONS
CONS
How to Implement
#1 Basic Sample
The singleton patterns have six basic samples which show below:
public sealed class Singleton
{
public static Guid guid { get; set; }
private Singleton() { }
private static Singleton instance;
public static Singleton GetInstance()
{
if (instance == null)
{
guid = Guid.NewGuid();
instance = new Singleton();
}
return instance;
}
public static Guid someBusinessLogic() => guid;
}
class Program
{
static void Main(string[] args)
{
// The client code.
var s1 = Singleton.GetInstance();
var s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Singleton work, variables contain same instances.");
Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
}
else
Console.WriteLine("Singleton failed, variables contain different instances.");
Console.ReadKey();
}
} The above sample source code is not thread-safe. Two various tasks can pass the if-statement condition, which creates instances that violate the singleton pattern concepts. Maybe the instances have been made before the c sharp compiler mechanism evaluates the expression. However, the computer’s memory doesn’t ensure other threads will see the new instance memory values unless the other thread’s source code has passed suitable memory barriers.
2. Simple thread safety via locking
public sealed class Singleton
{
public static Guid guid { get; set; }
private Singleton() { }
private static Singleton instance;
private static readonly object padlock = new object();
public static Singleton GetInstance()
{
lock (padlock)
{
if (instance == null)
{
guid = Guid.NewGuid();
instance = new Singleton();
}
return instance;
}
}
public static Guid someBusinessLogic() => guid;
}
class Program
{
static void Main(string[] args)
{
// The client code.
var s1 = Singleton.GetInstance();
var s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Singleton work, variables contain same instances.");
Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
}
else
Console.WriteLine("Singleton failed, variables contain different instances.");
Console.ReadKey();
}
} The second sample implements the thread-safe concepts. The thread can lock on share objects and check whether the instance has been created by other source code before creating the instance. This sample can solve the memory barrier issues and ensures the only one task will create an instance. Unfortunately, this sample will affect the performance suffers because a lock condition is acquired every time the instances are requested.
3. Double-checked locking
public sealed class Singleton
{
public static Guid guid { get; set; }
private Singleton() { }
private static Singleton instance;
private static readonly object padlock = new object();
public static Singleton GetInstance()
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
guid = Guid.NewGuid();
instance = new Singleton();
}
}
}
return instance;
}
public static Guid someBusinessLogic() => guid;
}
class Program
{
static void Main(string[] args)
{
// The client code.
var s1 = Singleton.GetInstance();
var s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Singleton work, variables contain same instances.");
Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
}
else
Console.WriteLine("Singleton failed, variables contain different instances.");
Console.ReadKey();
}
} The third sample has the double-check mechanism, but the performance issue still exists without solving it. Unfortunately, this sample has four downsides to the singleton pattern shows below:
instance variable volatile can make it work, as would explicit memory barrier calls, although in the latter case even experts can’t agree exactly which barriers are required. I tend to try to avoid situations where experts don’t agree what’s right and what’s wrong!From C# in depth – Implementing the Singleton Pattern in C#
4. Safety throught initialization
public sealed class Singleton
{
public static Guid guid { get; set; }
static Singleton() { }
private Singleton() { }
private static readonly Singleton instance = new Singleton();
public static Singleton GetInstance()
{
guid = Guid.NewGuid();
return instance;
}
public static Guid someBusinessLogic() => guid;
}
class Program
{
static void Main(string[] args)
{
// The client code.
var s1 = Singleton.GetInstance();
var s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Singleton work, variables contain same instances.");
Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
}
else
Console.WriteLine("Singleton failed, variables contain different instances.");
Console.ReadKey();
}
} Static constructor characteristics in c# are appointed to execute. Only when the class instance creates or the static members are referenced and run only once per AppDomain. Whatever else situation, it must be running faster than other adding source code for checking a new instance in previous samples. This solution will make a couple of wrinkles that show below:
Instance, the first reference to those members will involve creating the instance. This is corrected in the next implementation.beforefieldinit. Unfortunately, the C# compiler (as provided in the .NET 1.1 runtime, at least) marks all types which don’t have a static constructor (i.e. a block which looks like a constructor but is marked static) as beforefieldinit. It will affects performance.From C# in depth – Implementing the Singleton Pattern in C#
This sample is a shortcut method for creating instances that are a public static read-only variable and getting rid of the property entirely, which lets the basic skeleton code is tiny.
5. Safe and fully lazy static initialization
public sealed class Singleton
{
public static Guid guid { get; set; }
private Singleton() { }
public static Singleton GetInstance {
get {
guid = Guid.NewGuid();
return Nested.instance;
}
}
private class Nested
{
static Nested()
{ }
internal static readonly Singleton instance = new Singleton();
}
public static Guid someBusinessLogic() => guid;
}
class Program
{
static void Main(string[] args)
{
// The client code.
var s1 = Singleton.GetInstance;
var s2 = Singleton.GetInstance;
if (s1 == s2)
{
Console.WriteLine("Singleton work, variables contain same instances.");
Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
}
else
Console.WriteLine("Singleton failed, variables contain different instances.");
Console.ReadKey();
}
} This sample instance uses the embedding method for the static members, which only happens the first time calling. It means it is fully lazy, but all the performance benefits of the previous ones still exist. The embedding method can be called the enclosing class’s private member. However, it isn’t true; therefore, the need for an instance to be internal here. It doesn’t bring any other problems as the class itself is private, but it can let the source code become complex.
6. Using .NET 4.X’s Lazy<T> type
public sealed class Singleton
{
public static Guid guid { get; set; }
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton GetInstance
{
get {
guid = Guid.NewGuid();
return lazy.Value;
}
}
public static Guid someBusinessLogic() => guid;
}
class Program
{
static void Main(string[] args)
{
// The client code.
var s1 = Singleton.GetInstance;
var s2 = Singleton.GetInstance;
if (s1 == s2)
{
Console.WriteLine("Singleton work, variables contain same instances.");
Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
}
else
Console.WriteLine("Singleton failed, variables contain different instances.");
Console.ReadKey();
}
} The #6 sample is base on the project’s NET 4 or higher, then using the System.Lazy type, which can make let developers easy to use it. The developers only do a thing that uses a delegate to the constructor, which calls the Singleton constructor, which is done with a lambda expression and implicitly uses LazyThreadSafetyMode.ExecutionAndPublication as the thread-safety mode for the Lazy.
#2 Web Application Project
Step 1 Create an interface class whose name sets “IOperation” under the Core project. Create another class file which name sets “Operation” under the Infra project.
Step 2 The “Operation” class file inherits the IOperation interface class file under the Infra project. The “IOperationSingleton” interface class adds a GET guid string method and inherits the IOperation interface class; then, the “Operation” class file inherits it.
The IOperation file source code shows below:
public interface IOperation
{
string OperationId { get; }
}
public interface IOperationTransient : IOperation
{
new string OperationId();
}
public interface IOperationScoped : IOperation
{
new string OperationId();
}
public interface IOperationSingleton : IOperation
{
new string OperationId();
} Step 3 Add the Controller file and the View file under the web project, then calling the IOperation class’s way from the Controller file to layout the View file. The Controller file name sets “SingletonController.” The View file part only creates the “Index” page under the web project’s Views folder.
Step 4 Add the Singleton in the startup.cs file, which is under the web project.
services.AddSingleton<IOperationSingleton, Operation>(); Reference
What is the API gateway? An API gateway is an API management tool that sits…
The .NET 5 SDK is a kind of milestone in the .NET world. The .NET…
In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software…
In the field of software engineering, the interface segregation principle (ISP) states that no code…
Subtype Requirement: Let be a property provable about objects of type T. Then should be true for objects of type S where S is…
In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be…
View Comments