博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET Core中延迟单例另一种写法【.NET Core和.NET Framework的beforefieldinit差异】
阅读量:6590 次
发布时间:2019-06-24

本文共 4106 字,大约阅读时间需要 13 分钟。

1.BeforeFieldInit是什么

   前段时间在反编译代码时无意间看到在类中有一个BeforeFieldInit特性,处于好奇的心态查了查这个特性,发现这是一个关于字段初始化时间的特性【提前初始化字段】,下面先来看一下这个特性在.net framework中的作用

class Foo{   public static String x = GetStr("初始化 Foo 静态成员字段");   public static String GetStr(String str)  {       Console.WriteLine(str);       return str;  }}

   在上面Foo类中只定义了一个静态字段x和一个静态方法GetStr的方法,在这里需要关注的是静态字段x的初始化时机

static void Main(string[] args){      Console.WriteLine("Main方法开始");      Foo.GetStr("手动调用Foo.GetSring()方法");      String y = Foo.x;}

  在Main中简单的调用静态方法和静态字段,我们知道静态字段的赋值是在静态构造函数中进行的,那么输出顺序应该是 “Main方法开始”,”初始化Foo静态成员字段“,”手动调用Foo.GetString()方法“,但是真的是这样吗,答案是错的

  可以看到静态成员字段的初始化是在最开始,那么为什么会这样呢,我们将代码反编译IL后会发现在类中具有一个beforefieldinit特性,

.class private auto ansi beforefieldinit BeoreFieldInitTest2.Foo    extends [mscorlib]System.Object{
} // end of class BeoreFieldInitTest2.Foo

   那么BeforeFieldInit是什么,我找到了一篇有对BeforeFieldInit的详细讲解,在这里也不过多介绍,

2.取消BeforeFieldInit加载

  那么该怎么取消beforefieldinit特性呢,其实很简单,只需要在类中加入一个静态构造函数即可

class Foo{     public static string x = GetStr("初始化 Foo 静态成员字段");      //空的静态构造函数      static Foo(){}     public static String GetStr(String str)     {         Console.WriteLine(str);          return str;      }        }

  然后此时输入就如我们所猜测那样

 并且反编译可以看到IL代码也取消了beforefieldinit特性

.class private auto ansi BeoreFieldInitTest2.Foo    extends [mscorlib]System.Object{
} // end of class BeoreFieldInitTest2.Foo

  下面就该进入正题,来看看.NET Core中不一样的BeforeFieldInit  

3.BeforeFieldInit在.NET Core 中的差异

  将最开始的代码在.NET Core中跑一跑会发现跟.NET Framework不一样的操作

class Program    {        static void Main(string[] args)        {            Console.WriteLine("Main方法开始");            Foo.GetStr("手动调用Foo.GetSring()方法");            String y = Foo.x;        }    }    class Foo    {        public static string x = GetStr("初始化 Foo 静态成员字段");        public static String GetStr(String str)        {            Console.WriteLine(str);            return str;        }    }

 

  可以看到在.NET Core并没有像.NET Framework那样进行提前加载,并且加载貌似还延迟了,反编译代码可以看到beforefieldinit特性还在Foo类上

.class private auto ansi beforefieldinit BeforeFieldInitTest.Foo    extends [System.Runtime]System.Object{
} // end of class BeforeFieldInitTest.Foo

    那么在.NET Core加入静态构造函数会怎么呢?怀着各种疑惑进行测试

class Program{     static void Main(string[] args)     {          Console.WriteLine("Main方法开始");          Foo.GetStr("手动调用Foo.GetSring()方法");          String y = Foo.x;      } }class Foo{      public static string x = GetStr("初始化 Foo 静态成员字段");      //空的静态构造函数      static Foo() { }      public static String GetStr(String str)      {          Console.WriteLine(str);          return str;      }}

    可以看到.NET Core中加入静态构造函数以后输出跟.NET Framework一致,也就说可以猜测.NET Core运行时对beforefieldinit特性进行了优化,当然这也只是我的猜测

4.利用.NET Core中beforefieldinit实现的单例

   在.NET Framework中我们都是使用Lazy<>类来创建延迟加载单例,但是我们可以看到在.NET Core中beforefieldinit是延迟加载的,所以我们直接可以使用此方法来创建延迟安全单例,

class Program{    static void Main(string[] args)    {         Console.WriteLine("Main方法开始");         Foo.GetStr("手动调用Foo.GetSring()方法");         Console.WriteLine("我是分隔符");          Console.WriteLine("我是分隔符");          var foo= Foo.CreateInstance;     }}class Foo{     public static Foo CreateInstance { get;  } = new Foo();     private Foo()     {         Console.WriteLine("创建了Foo实例");     }     public static String GetStr(String str)     {         Console.WriteLine(str);         return str;     } }

  运行结果可以看到创建实例被延迟了,

  当然,这种创建单例也是有缺点的,当类中还有其它静态字段或属性时,并且在外部进行了调用,那么此时也会初始化此属性

class Program{     static void Main(string[] args)     {         Console.WriteLine("Main方法开始");         Foo.GetStr("手动调用Foo.GetSring()方法");         var y = Foo.x;//调用静态字段/属性         Console.WriteLine("我是分隔符");         Console.WriteLine("我是分隔符");         var foo= Foo.CreateInstance;     } } class Foo {     public static string x = GetStr("初始化 Foo 静态成员字段"); //加入了静态字段或属性     //public static String X { get; set; } = GetStr("初始化 Foo 静态成员字段");     public static Foo CreateInstance { get;  } = new Foo();     private Foo()     {         Console.WriteLine("创建了Foo实例");     }     public static String GetStr(String str)     {         Console.WriteLine(str);         return str;     }}

   也就是说在.NET Core中beforfieldinit特性时当有一个静态变量被使用时就初始化所有静态变量

 

转载地址:http://jfuio.baihongyu.com/

你可能感兴趣的文章
数据结构与算法 | Leetcode 19. Remove Nth Node From End of List
查看>>
一起来读you don't know javascript(一)
查看>>
[LeetCode] 862. Shortest Subarray with Sum at Least K
查看>>
【分享】终端命令工具 自动生成vue组件文件以及修改router.js
查看>>
[LeetCode] Student Attendance Record I
查看>>
PHP回顾之多进程编程
查看>>
spring boot + redis
查看>>
Ajax技术细节
查看>>
nuxt.js部署vue应用到服务端过程
查看>>
删除数组中的指定元素 | JavaScript
查看>>
CSS3+JS实现静态圆形进度条【清晰、易懂】
查看>>
关于树形插件展示中数据结构转换的算法
查看>>
图片加载框架之Fresco
查看>>
Spotify开源其Cassandra编排工具cstar
查看>>
高性能web建站规则(将js放在页面底部)
查看>>
Java EnumMap工作原理及实现
查看>>
阐述Spring框架中Bean的生命周期?
查看>>
虚拟内存管理
查看>>
注水、占坑、瞎掰:起底机器学习学术圈的那些“伪科学”
查看>>
大数据小视角1:从行存储到RCFile
查看>>