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

.NET Core中延迟单例另一种写法【.NET Core和.NET Framework的beforefieldinit差异】的更多相关文章

  1. Java基础系列-单例的7种写法

    原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755322.html 一.概述 Java中单例有7种写法,这个是在面试中经常被问到的内容,而且有时候 ...

  2. Java并发编程中的设计模式解析(二)一个单例的七种写法

    Java单例模式是最常见的设计模式之一,广泛应用于各种框架.中间件和应用开发中.单例模式实现起来比较简单,基本是每个Java工程师都能信手拈来的,本文将结合多线程.类的加载等知识,系统地介绍一下单例模 ...

  3. 「Android」单例的五种写法

    单例 发现博客园可以很好的设置自己的博客文章的展示,很开心,然后特此发一篇 其实这几种写法大家应该都会的,就权当拿来记录一下吧,以后复习巩固也比较方便. 这篇文章中的代码,来自一篇视频(我想找视频贴上 ...

  4. java23种设计模式之二: 单例设计模式(6种写法)

    目的:在某些业务场景中,我们需要某个类的实例对象的只能有一个,因此我们需要创建一些单例对象. 本文共有6种写法,仅供参考 1.饿汉式 优点: 在多线程情况下,该方法创建的单例是线程安全的(立即加载) ...

  5. java单例的几种写法

    转载出处:http://cantellow.javaeye.com/blog/838473 第一种(懒汉,线程不安全): public class Singleton { private static ...

  6. iOS单例的两种实现

    单例模式算是开发中比较常见的一种模式了.在iOS中,单例有两种实现方式(至少我目前只发现两种).根据线程安全的实现来区分,一种是使用@synchronized,另一种是使用GCD的dispatch_o ...

  7. 【cocos2d-js官方文档】二十五、Cocos2d-JS v3.0中的单例对象

    为何将单例模式移除 在Cocos2d-JS v3.0之前.全部API差点儿都是从Cocos2d-x中移植过来的,这是Cocos2d生态圈统一性的重要一环.可惜的是,这样的统一性也在非常大程度上限制了C ...

  8. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

  9. 在Swift中实现单例方法

    在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...

随机推荐

  1. 如何查看程序所占端口号和IP

    如何查看程序所占端口号和IP 一个软件可能占用多个端口拥有多个目标IP,下面以FQ工具Lantern为例,说明端口查看方法: 1.借助第三方软件查看 如果你电脑上安装了360等优化工具,可能会自带查看 ...

  2. verilog实现两个数的最大公因数

    module gcd(clk,clr,go_i,x_i,y_i,d_o); input clk,clr; input go_i; :] x_i,y_i; :] d_o; :] x,y,r; alway ...

  3. 漫说996icu黑名单

    以实际行动声援996icu项目. https://github.com/996icu/996.ICU/blob/master/blacklist/blacklist.md 996公司黑名单,京东,华为 ...

  4. java中利用dom4j解析XML文件

    官网下载Dom4j地址:https://dom4j.github.io/ 注意:使用Dom4j开发,需下载dom4j相应的jar文件 题目:后台利用dom4j解析student.xml文件,并返回Li ...

  5. 利用python搭建Powersploit powershell脚本站点

    powershell脚本站点的搭建 一.Powersploit Powersploit是一款基于powershell的后渗透(Post-Exploitation)框架,集成大量渗透相关模块和功能. 下 ...

  6. SpringDataJpa的批量 保存 修改 操作

    SpringDataJpa进行修改数据库操作有两种方式: 一.调用保存实体的方法 1.保存一个实体:repository.save(T entity) 2.保存多个实体:repository.save ...

  7. 安装window 7系统----计算机经验

    上期我们已经成功制作了U盘启动并且也成功进入了PE系统了,在PE微型系统中,除了简单的装系统来恢复C盘,还有什么功能你们可以使用的呢?如果这一期我没有把其他内容讲解的话,千万别乱搞,到时我可能会讲解几 ...

  8. 常用判断重复记录的SQL语句

    1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断select * from people where peopleId in (select   peopleId  fro ...

  9. zookeeper-02 部署

    1. 主机规划 主机名称 外网IP[外部访问] 内网IP 操作系统 备注 安装软件 docker01 10.0.0.11 172.16.1.11 CentOS 7.2 zookeeper-3.4.5[ ...

  10. 【弱省胡策】Round #5 Count

    [弱省胡策]Round #5 Count 太神仙了. \(DP\)做法 设\(f_{n,m,d,k}\)表示\(n*m\)的矩阵,填入第\(k\)个颜色,并且第\(k\)个颜色最少的一列上有\(d\) ...