单例模式静态变量初始化问题

举报
王阿毛 发表于 2020/04/16 17:56:19 2020/04/16
【摘要】 最近在写一个项目时用到了单例模式,但是非常奇怪的是在我第一次调用该单例之前,就已经被实例化了。为了弄清楚到底是怎么回事,在网上查询了很多资料,记录如下:对于一个类的静态变量,普遍认为是在第一次使用该类是进行初始化所有该类静态变量和静态方法 private static readonly object LockObj = new object(); private st...

最近在写一个项目时用到了单例模式,但是非常奇怪的是在我第一次调用该单例之前,就已经被实例化了。为了弄清楚到底是怎么回事,在网上查询了很多资料,记录如下:

对于一个类的静态变量,普遍认为是在第一次使用该类是进行初始化所有该类静态变量和静态方法

      private static readonly object LockObj = new object();
        private static TInstance _instance;
        public static TInstance Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (LockObj)
                    {
                        if (_instance == null)
                        {
                            _instance = new TInstance();
                        }
                    }
                }
                return _instance;
            }
        }

以上就是一个非常典型的单例模式,但是在实际调用和调试的过程中会发现,在第一次调用时,_instance就已经被实例化了,为此我专门写了个测试用demo

  class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主程序开始执行");
            GetInstance<Class1>.Instance.WriteStr("调用静态方法");
            Console.WriteLine("静态方法执行完毕");     
      
            Console.ReadKey();
        }
    }
   public class GetInstance<TInstance> where TInstance : class, new()
    {
        private static readonly object LockObj = new object();
        private static TInstance _instance;
        public static TInstance Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (LockObj)
                    {
                        if (_instance == null)
                        {
                            _instance = new TInstance();
                        }
                    }
                }
                return _instance;
            }
        }
     

    }
  public class Class1
    {
        public Class1()
        {
            Console.WriteLine("初始化 Class1");
        }
        
        public void WriteStr(string v)
        {
            Console.WriteLine(v);
        }

执行结果:

image.png


按理来说,初始化 class1这句话应该是在调用静态方法之后才会出现,却出现在了前面,难道说静态成员不是在类第一次被使用时进行初始化,而是在调用方法前就已经初始化了?

在网上查了很多资料后,终于找到了问题所在,类中的隐藏属性beforefieldinit。

JIT编译器可以在首次访问一个静态字段或者一个静态/实例方法之前,或者创建类型的第一个实例之前,随便找一个时间生成调用。具体调用时机由CLR决定,它只保证访问成员之前会执行(隐式)静态构造函数,但可能会提前很早就执行。

这也就解释了我们之前遇到的情况,而且也明确了并不一定是在调用方法前的那一刻

MSDN上查静态构造函数里有提到该属性。也可以TypeAttributes 枚举里看到一个叫做BeforeFieldInit的属性

BeforeFieldInit1048576

指定调用此类型的静态方法并不强制系统初始化此类型。

如果不想这样的话将构造函数用static 修饰即可解决,那么beforefieldinit属性就会被precise属性替换掉,这样就可以确保静态成员会在类第一次使用之前的那一刻进行初始化。

  


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。