zoukankan      html  css  js  c++  java
  • BeforeFieldInit的小叙

    BeforeFieldInit是什么

    上片的文章中我们看到了有静态构造函数,和没有静态构造函数,代码的执行顺序有着显著的区别。然后,我们反编译了下代码,发现了在类中有一个BeforeFieldInit特性,通过查各处资料,发现这是一个关于字段初始化时间的特性【提前初始化字段】,下面先来看一下这个特性在.net framework中的作用。摘取了别人的一份Demo:

    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;
    }
    运行的结果如下:

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

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

    这里是对beforefieldinit的一个介绍 点我

    如果想要取消BeofreFieldInit的话,可以显式的写静态构造函数

    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  

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

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

     那么在.NET Core加入静态构造函数?

     

    可以看到.NET Core中加入静态构造函数以后输出跟.NET Framework一致

    在.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特性时当有一个静态变量被使用时就初始化所有静态变量

    参考:https://www.cnblogs.com/yan7/p/9187874.html

  • 相关阅读:
    挂载在snap的/dev/loop占用100%问题
    机器学习3- 一元线性回归+Python实现
    机器学习-2 模拟评估与选择
    机器学习-1 绪论
    Java面试系列第4篇-HashMap相关面试题
    Java面试系列第3篇-类的加载及Java对象的创建
    Java面试系列第2篇-Object类中的方法
    Java面试系列第1篇-基本类型与引用类型
    第3篇-如何编写一个面试时能拿的出手的开源项目?
    第2篇-如何编写一个面试时能拿的出手的开源项目?
  • 原文地址:https://www.cnblogs.com/wwkk/p/10321776.html
Copyright © 2011-2022 走看看