单例模式_静态构造函数实现和IoDH实现

一.前言

      单例模式,简单字面意思就是整个程序中只进行一次初始化的操作。相对于静态类,单例模式能做到延迟加载,以及类继承。

      目前有6+种实现方式。本文只记录“静态构造函数下的单例模式”和“Initialization Demand Holder(IoDH)”。其他部分在文末有转载链接可以查看。

二.代码记录

        2.1  静态构造函数实现单例模式

             2.1.1 执行记录

          这里我们直接上代码,根据结果进行记录:

          字段x初始化会在构造函数前面先执行。(重点。后面单例模式里面执行代码和想象中不同,考虑是这个原因。)

    public class SingletonTest
    {
        public static string x = EchoAndReturn("A_In type initializer");

        /// <summary>
        /// 当没有写静态构造函数时,框架会自动生成
        /// 导致静态字段的初始化跑到了静态方法调用之前
        /// 造成对象的提前初始化
        /// </summary>
        static SingletonTest()
        {
            x = "A_static";
            Console.WriteLine("A_static init");
        }

        public SingletonTest()
        {
            x = "A_nonstatic";
            Console.WriteLine("A_nonstatic init");
        }

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

     对应main函数如下:

 static void Main(string[] args)
        {
            Console.WriteLine("Starting Main");
            //SingletonTest_inherit b = new SingletonTest_inherit();

            SingletonTest.EchoAndReturn("Echo!");
            Console.WriteLine("After echo");

            string y = SingletonTest.x;
            if (!string.IsNullOrEmpty(y))
            {
                Console.WriteLine(y);
            }
            //y = SingletonTest_inherit.x;
            //if (!string.IsNullOrEmpty(y))
            //{
            //    Console.WriteLine(y);
            //}

            Console.ReadKey();
        }

                       

可以看到:

1.程序运行--》2.执行main函数--》3.使用到静态SingletonTest--》4.静态字段x的初始化--》5.静态构造函数的初始化--》6.静态函数EchoAndReturn的实现

--》字段x的值由于执行顺序,不是默认赋值的"A_In type initializer",而是静态构造函数中赋值的x = "A_static";

如果这里不加静态构造函数?

1.程序运行--》2.静态类型的初始化,静态SingletonTest、字段x提前初始化--》3.执行main函数。

这里在文末的博文中提到是:

       在类中实现静态构造函数,那beforefieldinit属性就会被precise属性替换,确保静态成员会在类第一次使用之前的那一刻进行初始化。如果不显式实现,静态成员会在类第一次使用之前的任何时间初始化(由CLR智能决定)。

比较得出:

     显式静态构造函数使对象在被调用的时候才初始化,避免了static类型在程序启动的时候就提前初始化的问题。有利于程序的快速启动与内存的控制。

            2.1.2 单例模式实现

    public class SingletonTest
    {
        private static readonly SingletonTest _instance = new SingletonTest();
        static SingletonTest()
        {
        }
        private SingletonTest()
        {
        }

        public static SingletonTest Instance
        {
            get
            {
                return _instance;
            }
        }
    }

1.将构造函数private;

2.显式实现static构造函数;

3.创建私有静态实例_instance并初始化;

4.public开放实例对外访问接口 Instance 属性。

这样避免了静态类型的提前初始化,同时直接在初始化时候赋值的方式也避免了需要加锁的问题。

           2.1.3 单例模式执行顺序

public class SingletonTest
    {
        private static readonly SingletonTest _instance = new SingletonTest();
        static SingletonTest()
        {
            Console.WriteLine("static init console");
            x = "static init";
        }
        private SingletonTest()
        {
            Console.WriteLine("nonstatic init console");
            x = "nonstatic init";
        }
        public static SingletonTest Instance
        {
            get
            {
                Console.WriteLine("Instance");
                return _instance;
            }
        }
        //测试静态字段,对执行顺序无影响,实际使用应该为非static,同时操作应该通过XX,不能直接操作本字段
        private static string x = "xxxx";
        public string XX
        {
            get { return x; }
            private set { x = value; }
        }
    }

main函数中输出 Console.WriteLine( SingletonTest.Instance.XX);

执行结果:

                     

1.程序启动--》2.遇到类SingletonTest--》3.优先初始化static属性_instance(Instance没有set,显式写也不会执行)--》4._instance=new SingletonTest()进行实例化--》5.完成static属性的初始化后进行static构造函数的初始化--》6.调用SingletonTest.Instance--》7.获取结果XX得"static init"

--》注意这里不是先static init,然后才nonstatic init。因为属性的初始化优先于static构造函数。所以最后的结果是静态构造函数得执行顺序在nonstatic的后面。

           2.1.4 继承问题

    这里题外话记录一下继承时的表现,进一步展示函数执行顺序:

增加子类型:

    public class SingletonTest_inherit : SingletonTest
    {
        static SingletonTest_inherit()
        {
            x = "B_static";
            Console.WriteLine("B_static init");
        }

        public SingletonTest_inherit()
        {
            x = "B_nonstatic";
            Console.WriteLine("B_nonstatic init");
        }
    }

执行结果:

               

子对象的静态构造函数没有执行。

如果这里增加实例化?

              

1.父类型字段x初始化--》2.父类型static构造函数执行--》3.子类型static构造函数执行--》4.父类型构造函数执行--》5.子类型构造函数执行

--》这里父类型和子类型共用同一个字段x,导致字段x的赋值被子类型重写。

             

 

  2.2 IoDH实现

      2.2.1单例模式实现

推荐单例模式使用该方式。在类内部定义内部类来实现单例模式。

    public class SingletonTest
    {
        private class InnerCLass
        {
            static InnerCLass() { }
            internal static SingletonTest instance = new SingletonTest();
        }
        private SingletonTest() { }
        public static SingletonTest Instance
        {
            get { return InnerCLass.instance; }
        }
    }

     2.1.3 单例模式执行顺序

    public class SingletonTest
    {
        private class InnerCLass
        {
            static InnerCLass()
            {
                Console.WriteLine("InnerCLass static");
            }
            internal static SingletonTest instance = new SingletonTest();
        }
        private SingletonTest() {
            Console.WriteLine("SingletonTest nonstatic");
        }
        public static SingletonTest Instance
        {
            get {
                Console.WriteLine("Instance");
                return InnerCLass.instance; }
        }

        public string XX = "aaa";
    }

三.相关参考链接

https://www.cnblogs.com/rush/archive/2011/10/30/2229565.html    ---主要参考博文

https://www.cnblogs.com/jiagoushi/p/3775046.html                         ---提供继承方面的探讨

https://blog.csdn.net/abc524061/article/details/57086267?utm_source=itdadao&utm_medium=referral    ---对第一个博文进行扩展和实践

猜你喜欢

转载自blog.csdn.net/Yao_2333/article/details/81203878
今日推荐