C# 关于值类型构造和静态构造 | 狂吼的面包圈
因为梦想
我们一直在努力

C# 关于值类型构造和静态构造

值类型构造

  • 关于引用类型的构造 http://www.ravedonut.com/archives/5108
  • C#编译器不会为值类型生成默认的无参构造器
  • 这里的值类型一般是指Struct结构类型
  • 虽然可以在使用结构类型的时候定义无参构方法,但是这种构造方法的执行只能写代码显式调用。
  • (部分编译器也会进行提示,如果你定义了无参构造会收到一个错误信息)
  • C#里无法这样定义,但是如果直接用IL定义,那是可以的。

静态类型构造

  • C#允许引用类型和值类型定义静态的构造方法
  • 虽然允许值类型定义,但是别这么做,因为CLR有时不会调用值类型的静态类型构造
    例子:  VS里开的C#工程,直接复制代码跑下可发现是不执行的
  • 静态构造方法会自动被标记为私有的
    如果强行标记为公有则会出现提示 如图:
  • 静态构造IL里查阅
  • .cctor 就是静态构造方法了,另外也可以在上面看到默认就是私有的。一般的C#方法默认的话应该是保护权限。
  • 在进行一个对比,现在将静态构造修改成为一个正常的构造方法
    IL查看
  • 根据对比可以明显发现,正常的构造方法是有一个Call的过程的。而静态是没有这个过程的

静态构造的性能

  • JIT编译方法的时候,要决定是否在方法中生成一个对静态构造的调用
  • 如果JIT决定调用,那么还需要确定在哪里进行调用,毕竟静态构造只执行一次
  • 所以将会产生如下两种可能:

    1- JIT编译器可以刚好在创建类型的第一个实例之前,或者刚好在访问类的一个非继承的字段或成员之前生成这个调用。这种情况称为“精确(Precise)语义”,CLR如此情况下拿捏的正正好

    2- 有了精确就有了不精确,JIT编译器也可以在首次访问一个静态字段或者一个静态/实例方法之前,或者在调用一个实例构造之前,随便找个时间空隙生成调用,这个情况称为“字段初始化之前(before-field-init)语义”,CLR这种情况只是单纯的保障在这个静态之前它已经初始化好了。

  • 一般情况下,字段初始化之前肯定是第一考虑的,毕竟这样做最方便,默认构造情况下语言的编译器会选择对定义的类型来说最恰当的一种语义,并在类型定义元数据表的行中设置beforefieldinit标志,从而告诉CLR这个选择
  • 下面进行一个实验

 

  • 运行结果:

 

  • IL分析
  • 结论: 根据上述情况,一般情况下如非必要,还是直接使用默认的before-field-init就可以了。或者根据自己的需要进行空跑一次,让系统提前执行下。
转载请注明原出处:狂吼的面包圈 » C# 关于值类型构造和静态构造