C#单例模式和静态构造函数 - chunlieater/chunlifeet GitHub Wiki

单例模式可以用两种方法来做: 1 用静态函数赋值。2 用静态构造函数赋值。 构造函数都是私有,静态构造函数是公共,静态构造函数在程序中只执行一次,不能加修饰符,不能有参数。

  • 1

  • public static ClassA instance;

  • pullic static ClassA Instance{

  • get{
    
  •    if(instance ==null){
    
  •       instance = new ClassA();
    
  •    }
    
  •    return instance;
    
  • }
    
  • }

  • private ClassA(){}

  • 2

  • public static ClassB instance;

  • static ClassB{

  • instance = new ClassB();
    
  • }

  • private ClassB(){}

静态变量的初始化赋值顺序:

静态变量或静态函数被第一次调用时按照以下顺序赋值:1 开辟变量空间,赋默认值(int型为0,object型为null)。2 查看变量列表中是否有赋值,有的话将其赋值。3 运行静态构造函数。 除了第一次调用之外的任何一次调用,都不用再走这个流程,直接返回当前的值就行了,就算是在初始化调用中进行第二次调用也是如此: 例子:

  • public class Chunli{

  • public static string legs = Cammy.legs;
    
  • static Chunli(){
    
  •    legs += "chunliLegs!"+2;
    
  • }

  • }

  • public class Cammy{

  • public static string legs = Chunli.legs;
    
  • static Cammy(){
    
  •     legs += "Cammylegs!"+1;
    
  • }
    
  • }

  • console.writeline(Chunli.legs);

  • console.writeline(Cammy.legs);

最后结果是 “Cammylegs1chunlilegs2” "cammylegs1"

分析:根据静态变量初始化的顺序理清即可。首先调用了Chunli.legs,legs变量开始初始化,首先给它赋默认值string.empty,然后看变量列表赋值, = 右边是Cammy.legs,所以Cammy的legs变量开始初始化,同样首先给legs赋默认值string.empty,然后变量列表赋值为 = Chunli.legs,Chunli.legs已经赋值成string.empty了,属于第二次调用,所以直接返回当前值string.empty,Cammy.legs = string.empty,然后再执行cammy的静态构造函数,最后Cammy.legs = string.empty1,并返回给Chunli.legs,最后执行chunli的静态构造函数,最后Chunli.legs = Cammylegs1chunlilegs2。

如果之前没有使用过静态成员变量或者方法,那么类的对象(实例)第一次被创建时,就会自动按照上面的顺序先调用静态流程,然后再进行非静态流程, 也就是说先给静态变量赋默认值,然后赋初始化值,然后调用静态构造函数,之后给非静态变量赋默认值,再赋初值,最后调用非静态构造函数创建实例。如果该类有父类,并且父类的静态成员没有被访问过,那么在其非静态构造函数开始时进行父类的初始化,流程与该类一致,父类初始化完毕,转回子类构造函数继续执行。

  • public class StaticTest{
  • private static StaticTest _instance;
  • public int x;
  • static StaticTest(){
  • Console.WriteLine("StaticConstruct");
    
  • }
  • public static StaticTest Instance(){
  • Console.WriteLine("StaticInstance");
  •     if(_instance==null){
    
  •         _instance = new StaticTest();
    
  •         _instance.x = 100;
    
  •     }
    
  •     return _instance;
    
  • }
  • private StaticTest(){
    
  • Console.WriteLine("Construct");
    
  • }
  • public static void Test(){
    
  • Console.WriteLine("StaticTest");
    
  • }
  • }
  • namespace myApp2
  • {
  • class Program
    
  • {
    
  •     static void Main(string[] args)
    
  •     {
    
  •         StaticTest.Test();
    
  •         StaticTest test = StaticTest.Instance();
    
  •     }  
    
  • }    
    
  • }

就这个列子分析下,在调用StaticTest.Test()时,系统先走静态初始化流程,也就是给_instance初始化为null,并执行静态构造函数,然后执行StaticTest.Test(),下面调用Instance单例函数时,因为静态初始化流程已经走完一次,所以直接执行该方法,在方法中初始化实例。

如果不先调用StaticTest.Test(),直接执行单例函数,那同理先走静态初始化流程,然后执行StaticTest.Instance()。