公鸭嗓,不成熟,飞机场,周迅到底有啥好?

小说:公鸭嗓,不成熟,飞机场,周迅到底有啥好?作者:卓丁邓更新时间:2019-03-26字数:12187

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://emigration.net.cn/array/19hasaqg5p.html

发布时间:2019-03-26 02:35:56

文化监理 - 黄胤然首倡文化新概念 汪国真是假诗人吗? 魏则西事件让百度在失去了什么? 刘墉:爱他!少骂他!一 有良心的孩子自己会觉悟 “舍”而后才会有所“得” 他说自己是潜力股,我就要答应他结婚,可笑吗? 青春期——改变人生的最后机会 这是关于我们为什么要努力最好的答案 希望邓森山的死能够引起天下父母的反思 何谓好名字

97543 10278 20304 54439 90717 64869 64469 35158 38783 27273 33034 90748 45650 72497 60536 22843 92001 26267 11900 97483 92695 73201 88273

我要说两句: (0人参与)

发布