基于System.Lazy的泛型单例类的静态构造函数能否省略?
问题1答复
保留静态构造函数的前提下,Lazy<YourClass>.Instance 绝对不会返回null,原因如下:
- C#规范明确要求:包含静态构造函数的类型,其所有静态字段的初始化操作,一定会在该类型的任何静态成员被首次访问、或者该类型被首次实例化之前完成,且初始化过程是线程安全的、全局仅执行一次。
- 你的代码中
_Instance字段在声明时就直接初始化赋值为new System.Lazy<YourClass>(),所以只要触发了Lazy<>类型的初始化,_Instance本身就不可能为null。 - 你使用了
System.Lazy的默认无参构造,其默认采用LazyThreadSafetyMode.ExecutionAndPublication线程安全模式,且泛型约束要求YourClass必须有公共无参构造函数,只要YourClass的无参构造本身不抛出异常,_Instance.Value也必然不为null。
哪怕你在其他类的类型初始化阶段访问该Instance属性,访问时会触发Lazy<>的类型初始化流程,完成_Instance的赋值,不会出现null的情况。
问题2答复
你完全可以移除这个空的静态构造函数,不会破坏安全性保证,原因如下:
- 没有静态构造函数的类型,编译器会添加
beforefieldinit标记,该标记仅允许运行时提前执行静态字段初始化,但不会改变「访问静态字段前必然完成初始化」的核心规则:只要你访问_Instance字段,运行时一定保证它的初始化器已经执行完毕,所以_Instance依然不可能为null。 - 有没有静态构造函数,影响的只是静态字段初始化的「时机早晚」,不会影响「初始化完成后才允许访问静态字段」的承诺。
补充说明
你之前遇到的NullReferenceException大概率和当前实现的这部分逻辑无关,可能的原因包括:
- 之前的旧实现没有在声明时就初始化
_Instance,而是把初始化逻辑放在了其他可能晚于访问的位置 YourClass的无参构造函数内部抛出了空引用异常,被你误判为Instance返回了null- 旧的单例实现没有用
System.Lazy,自行实现的线程安全逻辑有漏洞
内容的提问来源于stack exchange,提问作者NilNul
相关产品推荐
相关产品推荐

