.Net Framework 与 .Net Core中的静态构造函数

2021-05-06 14:27

阅读:467

标签:构造器   frame   这一   别人   并且   有意思   lazy   如何   构造函数   

起因

前几天在看书的时候看到一条内容 > 由于CLR保证一个类型构造器在每个AppDomain中只执行一次,而且(这种执行)是线程安全的,所以非常适合在类型构造器中初始化类型需要的任何单实例(Singleton)对象。
忽然想到,平时自己使用过程中都是通过Lazy来延迟化构建单例对象,就产生了一个疑问,使用Lazy跟直接使用静态构造函数有什么区别,有什么优缺点呢?

经过

抱着这个疑问,我查了一下相关的内容,发现一个很有意思的东西。
关于静态字段的初始化有两种写法

internal sealed class SomeType
{
????private static Int32 s_x = 5;
}
internal sealed class SomeType
{
????private static Int32 s_x;
      
????static SomeType()
????{
??????? s_x = 5;
????}
}

我在网上所查到的内容是,在使用第一种方法初始化字段的时候,需要添加一个为空的静态构造函数,这样能够保证,该类型是在被用到的时候才去初始化该静态字段。否则,该类型的字段初始化会被提前,甚至可能由于这个不可控的提前导致一些奇怪的问题。但是这种写法也有一个问题,那就是别人可能认为这个空的静态构造函数是无用的而删除这一部分。所以本人认为,下面这种写法更好一些(前提是.Net Framework)。

然后再来研究一下为什么会有这种奇怪的表现。这两种写法看起来没有什么区别,甚至于用JustDecomplie反编译dll出来的代码都是一致的。但是观察生成的IL就会发现他们的区别,第一种写法生成的类会存在beforefieldinit标志。由于编译器并不会提供默认的静态构造函数,所以在没有静态的时候,这个标志会将字段的初始化提前,而这种提前是不可控的。当手动写了静态构造函数,无论构造函数内是否有内容,这个标志都会被去掉,从而促使字段的初始化只有在真正第一次使用到该类的时候才会执行。

自己的尝试

看到这些东西之后,我也自己去做了一些尝试,发现自己的测试项目跑起来并没有这些问题,甚至于字段的初始化还有延迟加载的特性,只有真正用到了这个字段的时候才去初始化这个字段。

思来想去想了很久,突然发现自己的这个项目是一个.Net Core项目,难道说是.Net Core 与.Net Framework在这点的处理上有所不同?随后又去建了一个.Net Framework的项目,发现确实是存在提前初始化的情况。

两者存在不同这件事是可以确定的了,但是具体到底是怎么个不同呢?.Net Core 到底是如何处理beforefieldinit这个标志的呢?

我随后又查了一些相关的内容加上自己做的一些测试,最后得出结论如下:

  • 在存在静态构造函数的情况下,两者并没有什么区别,表现是一致的。
  • 在不存在静态构造函数的情况下,也就是类存在beforefieldinit标签的情况下
    • .Net Framework 会将字段的初始化提前,并且不可控
    • 而.Net Core 会做到延迟加载,只有当某一个字段真正被用到的时候,才会去初始化所有字段。所以在.Net Core中,是不是上面的第一种写法更好?毕竟有延迟加载的效果(虽然一个用到就会导致所有字段都初始化),当然关键还要看是否需要对字段初始化的时间精确控制,如果不需要精确控制,其实哪种写法都没差,这个视具体情况而定。

但是,我觉得既然需要延迟加载,用Lazy来控制每个字段的延迟看起来可控性更高一些。

后记

第一次写博客,有写的不对的地方还请见谅 (*^_^*)

.Net Framework 与 .Net Core中的静态构造函数

标签:构造器   frame   这一   别人   并且   有意思   lazy   如何   构造函数   

原文地址:https://www.cnblogs.com/LoveLan1314/p/12099476.html


评论


亲,登录后才可以留言!