单例模式静态变量初始化问题
最近在写一个项目时用到了单例模式,但是非常奇怪的是在我第一次调用该单例之前,就已经被实例化了。为了弄清楚到底是怎么回事,在网上查询了很多资料,记录如下:
对于一个类的静态变量,普遍认为是在第一次使用该类是进行初始化所有该类静态变量和静态方法
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); }
执行结果:
按理来说,初始化 class1这句话应该是在调用静态方法之后才会出现,却出现在了前面,难道说静态成员不是在类第一次被使用时进行初始化,而是在调用方法前就已经初始化了?
在网上查了很多资料后,终于找到了问题所在,类中的隐藏属性beforefieldinit。
JIT编译器可以在首次访问一个静态字段或者一个静态/实例方法之前,或者创建类型的第一个实例之前,随便找一个时间生成调用。具体调用时机由CLR决定,它只保证访问成员之前会执行(隐式)静态构造函数,但可能会提前很早就执行。
这也就解释了我们之前遇到的情况,而且也明确了并不一定是在调用方法前的那一刻
MSDN上查静态构造函数里有提到该属性。也可以TypeAttributes 枚举里看到一个叫做BeforeFieldInit的属性
BeforeFieldInit | 1048576 | 指定调用此类型的静态方法并不强制系统初始化此类型。 |
如果不想这样的话将构造函数用static 修饰即可解决,那么beforefieldinit属性就会被precise属性替换掉,这样就可以确保静态成员会在类第一次使用之前的那一刻进行初始化。
- 点赞
- 收藏
- 关注作者
评论(0)