6 Implementation _c# Tutorials for C # single case mode (Singleton)

Source: Internet
Author: User

1.1.1 Summary

In our day-to-day work, we often need to maintain a unique instance of the application. such as IO processing, database operations, and so on, because these objects occupy important system resources, so we have to limit the creation of these instances or always use a common instance, which is what we want to introduce today-- Single case mode (Singleton).

High frequency of Use

Single-piece Mode (Singleton): guarantees that a class has only one instance and provides a global access point to access it.

1.1.2 Body

Figure 1 Single-Example pattern (SINGLETON) structure diagram

The single case pattern (Singleton) is the most antagonistic of several creation patterns, and its main feature is not to generate a new instance based on a user program call, but to control the instance uniqueness of a type, which, by the above figure, we know contains only one role, that is Singleton, It has a private constructor, which ensures that the user cannot instantiate it directly through new. In addition, the pattern contains a static private member variable instance and a static public method instance (). The Instance () method examines and instantiates itself, and then stores it in a static member variable to ensure that only one instance is created.

Fig. 2 A single case pattern (Singleton) logical model

Next we will introduce the implementation of the different single case modes (Singleton) in 6. All of these implementations have the following similarities:

1. There is a private parameterless constructor that prevents other classes from instantiating it, and singleton classes should not be inherited, and if a singleton class allows inheritance then each subclass can create an instance, which violates the original intent of the Singleton pattern "unique instance."

2. A single instance class is defined as sealed, as the class mentioned earlier should not be inherited, so it is safe to define the class as not allowing derivation, but there is no requirement to define it.

3. A static variable is used to hold a reference to a single instance.

4. A public static method is used to obtain a reference to a single instance, or to create one if the instance is null.

Version thread not secure

 <summary>
///A Simple Singleton class implements.
</summary> public
Sealed class Singleton
{
  private static Singleton _instance = null;

  <summary>
  ///Prevents a default instance of 
  the///<see cref= "Singleton"/> class from being Crea Ted.
  </summary>
  Private Singleton ()
  {
  }

  ///<summary>
  ///Gets the instance.
  </summary> public
  static Singleton Instance
  {get
    {return _instance?? (_instance = new Singleton ()); }
  }
}

The above implementations apply to single-threaded environments, because multiple instances of the Singleton class may be available in a multithreaded environment. If there are two threads to judge

(Null = = _singleton), and the result is true, then two threads create instances of class Singleton, which violates the original intent of the Singleton pattern "unique instance."

version second-line security

 <summary>
///A Thread-safe Singleton class.
</summary> public
Sealed class Singleton
{
  private static Singleton _instance = null;
  private static readonly Object synobject = new Object ();

  Singleton ()
  {
  }

  ///<summary>
  ///Gets the instance.
  </summary> public
  static Singleton Instance
  {
    get
    {
      //Syn operation.
      Lock (Synobject)
      {return
        _instance?? (_instance = new Singleton ());}}}


The way it is implemented is thread-safe, first we create a static read-only process helper object, because lock ensures that when one thread is in the critical section of the code, another thread cannot enter the critical section (synchronous operation). If another thread tries to enter the locked code, it waits until the object is released. This ensures that multiple object instances are not created under multithreading. Only this implementation is synchronized, which is a bottleneck that affects system performance and adds additional overhead.

double-checked Locking

The question of how to implement the thread-safe implementation described above is to synchronize, so can we reduce the number of times we have to go through the operation? In fact, we just need to add a way to determine whether the instance is null before the synchronization operation, which can reduce the number of times it is passed, which is the classic double-checked locking method.

 <summary>
///double-checked locking implements a Thread-safe singleton class
///</summary> Public
sealed class Singleton
{
  private static Singleton _instance = null;
  Creates an Syn object.
  private static readonly Object synobject = new Object ();

  Singleton ()
  {
  } public

  static Singleton Instance
  {
    get
    {
      //double-checked Locking
      if (null = = _instance)
      {
        lock (synobject)
        {
          if (null = = _instance)
          {
            _ Instance = new Singleton ();
      }} return _instance;
    }
  }


Before introducing the fourth implementation approach, let's first understand what is that when a field is marked as a beforefieldinit type, the field initialization can occur before any field is referenced at any time. This sentence sounds a bit awkward, let's take a concrete example to introduce.

 <summary>
///defines a test class.
</summary>
class Test
{public
  static string x = Echoandreturn (' in type initializer ');

  public static string Echoandreturn (string s)
  {
    Console.WriteLine (s);
    return s;
  }
}

We have defined a class test that contains static fields and methods, but note that we do not define a static constructor.

Figure 3 The IL Code of the test class

Class Test
{public
  static string x = Echoandreturn (' in type initializer ');

  Defines a parameterless constructor.
  Static Test ()
  {
  } public

  static string Echoandreturn (string s)
  {
    Console.WriteLine (s);
    return s;
  }
}

Above we add a static constructor to the test class.

Figure 4 The IL Code of the test class

The difference between the IL code of the test class above shows that when the test class contains static fields and there is no static constructor defined, the class is marked as beforefieldinit.

Now someone may ask, "What's the difference between being labeled beforefieldinit and not marked?" OK now let's take a look at the differences in the following concrete examples!

 Class Test
{public
  static string x = Echoandreturn (' in type initializer ');

  Static Test ()
  {
  } public

  static string Echoandreturn (string s)
  {
    Console.WriteLine (s);
    return s;
  }
}

Class Driver
{public
  static void main ()
  {
    Console.WriteLine ("Starting Main");
    Invoke a static method on Test
    test.echoandreturn ("echo!");
    Console.WriteLine ("After Echo");
    Console.ReadLine ();

    The output result:
    //Starting Main
    //in type initializer
    //echo!
    After Echo      
  }
}

I believe everyone can get the answer, if you need to complete the initialization of static members before calling the Echoandreturn () method, the final output is as follows:

Figure 5 Output results

Then we add string y = Test.x in the main () method, as follows:

public static void Main ()
{
  Console.WriteLine ("Starting Main");
  Invoke a static method on Test
  test.echoandreturn ("echo!");
  Console.WriteLine ("After Echo");

  Reference a static field in Test
  string y = test.x;
  Use the ' value just to avoid compiler cleverness
  if (y!= null)
  {
    Console.WriteLine (' After field access '); c12/>}
  Console.readkey ();

  The output result:
  //in type initializer
  //starting Main
  //echo!
  After Echo
  //After field access

}

Figure 6 Output results

Through the output above, we can find that the initialization of static fields to the static method call before, Wo unimaginable ah!

Finally, we add a static constructor to the test class as follows:

 Class Test
{public
  static string x = Echoandreturn (' in type initializer ');

  Static Test ()
  {
  } public

  static string Echoandreturn (string s)
  {
    Console.WriteLine (s);
    return s;
  }
}
 

Figure 7 Output results

In theory, type initializer should occur in "echo!" Then and after Echo, but there are not unique results here, only when the test class contains a static constructor, can you ensure that the initialization of type initializer occurs in the "echo!" And before "after Echo".

So to make sure that type initializer occurs when the field is referenced, we should add a static constructor to the class. Let's now take a static approach to the single example pattern.

Static initialization

public sealed class Singleton
{
  private static readonly Singleton _instance = new Singleton ();

  Explicit Static constructor to tell C # compiler
  //not to mark type as beforefieldinit
  static Singleton ()
  {
  }

  <summary>
  ///Prevents a default instance of 
  the///<see cref= "Singleton"/> class from being CR eated.
  </summary>
  Private Singleton ()
  {
  }

  ///<summary>
  ///Gets the instance.
  </summary> public
  static Singleton Instance
  {get
    {return
      _instance
    }
  }
}

The above approach is simpler than the way it was introduced before, but it is really a way of Singleton that C # implements in a multithreaded environment. This method of static initialization is instantiated only when its fields are referenced.

Let's analyze static initialization with the IL code.

Figure 8 Static initialization Il code

First, there is no beforefieldinit modifier, because we have added a static constructor to initialize the static field when it is referenced, so even though many threads try to reference _instance, the static constructor is required to execute and Instance can be used after instantiation.

Deferred initialization

 <summary>
///delaies initialization.
</summary> public
Sealed class Singleton
{
  private Singleton ()
  {
  }

  ///<summary >
  ///Gets the instance.
  </summary> public
  static Singleton Instance {get {return nested._instance}

  } Private class Nested
  {
    //Explicit static constructor to tell C # compiler
    //not to mark type as Beforefiel Dinit
    Static Nested ()
    {
    }

    internal static readonly Singleton _instance = new Singleton ();
  }
}

Here we complete the initialization work in a static member of the nested class, which enables lazy initialization.

Lazy<t> type

 <summary>
///. NET 4 ' s lazy<t> type
///</summary> public
sealed class Singleton
{
  private static readonly lazy<singleton> Lazy =
    new Lazy<singleton> (() => new Singleton ());

  public static Singleton Instance {get {return lazy. Value; }

  Private Singleton ()
  {
  }
}

This approach is simple and performance-friendly, and also provides property isvaluecreated to check whether an instance has been created.

Specific examples

Now let's implement the load balancer using the single example mode (Singleton), first we define a server class that contains the server name and IP address as follows:

 <summary>
///represents a server machine
///</summary>
Class Server
{
  // Gets or sets server name public
  string name {get; set;}

  Gets or sets server IP address public
  string IP {get; set;}
}

Because the load balancer provides only one instance of an object for use by the server, we implement the load balancer using singleton mode (Singleton).

 <summary>///the ' Singleton ' class///</summary> sealed class LoadBalancer {private static readonly

  LoadBalancer _instance = new LoadBalancer ();
  Type-safe generic list of servers private list<server> _servers;

  Private Random _random = new Random (); Static LoadBalancer () {}//Note:constructor is ' private ' private loadbalancer () {//Load list of Availa
       BLE servers _servers = new List<server> {new server{Name = "Serveri", IP = "192.168.0.108"}, New server{name = "Serverii", IP = "192.168.0.109"}, new server{Name = "SERVERIII", IP = "192.168.0.110"} , new server{name = "Serveriv", IP = "192.168.0.111"}, new server{name = "Serverv", IP = "192.168.0.112"
  },
      };
  }///<summary>///Gets The instance through static initialization.
  </summary> public static LoadBalancer Instance {get {return _instance;} }//Simple, but EFFECtive load Balancer Public Server Nextserver {get {int r = _random. Next (_servers.
      Count);
    return _SERVERS[R];

 }
  }
}

The Load Balancer class above loadbalancer us to implement a single case pattern (Singleton) using a static initialization method.

 static void Main ()
{
  LoadBalancer b1 = loadbalancer.instance;
  B1. GetHashCode ();
  LoadBalancer b2 = loadbalancer.instance;
  LoadBalancer B3 = loadbalancer.instance;
  LoadBalancer b4 = loadbalancer.instance;

  Confirm These are the same instance
  if (B1 = b2 && B2 = = B3 && B3 = = B4)
  {
    Console.writel INE ("Same instance\n");
  }

  Next, load balance requests for a server
  loadbalancer balancer = loadbalancer.instance;
  for (int i = 0; i < i++)
  {
    string serverName = balancer. Nextserver.name;
    Console.WriteLine ("Dispatch Request to:" + serverName);
  }

  Console.readkey ();
}

Figure 9 LoadBalancer output Results

1.1.3 Summary

Advantages of the single case model:

The singleton pattern (Singleton) controls the number of instances of its objects, ensuring that access to the object is unique.

1. Instance control: A singleton pattern prevents other objects from instantiating themselves, ensuring that all objects have access to an instance.

2. Scalability: Because the class itself controls the instantiation process, the class has a corresponding scalability to change the instantiation process.

Disadvantages of the single example pattern:

1. System overhead. Although this overhead may seem small, a check is made on whether an instance exists each time the class instance is referenced. This problem can be solved by static instances.

2. Development confusion. When using an object of a singleton pattern (especially in the class library), the developer must remember that the object cannot be instantiated with the new keyword. Because developers do not see the source code in the class library, they are surprised when they find it impossible to instantiate a class.

3. Object life cycle. The single case model does not propose the destruction of the object. In the development language that provides memory management (for example, based on. NETFramework language), only the Singleton schema object itself can destroy the object instance because it has only a reference to the instance. In various development languages, such as C + +, other classes can destroy object instances, but doing so will result in a pointer pointing to an unknown inside the Singleton class.

Single Case Applicability

There is a requirement for using the singleton mode to use Singleton mode when a system requires that a class has only one instance. Conversely, if a class can have several instances coexisting, do not use singleton mode.

Do not use the single case mode to access global variables. This violates the intent of the single case pattern and is best placed in the static member of the corresponding class.

Do not make the database connection a single case, because a system may have multiple connections to the database, and in the case of a connection pool, the connection should be released as promptly as possible. Singleton mode can cause problems if resources are not released in time because of the use of static members to store class instances.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.