瞎掰:C#类型构造器
好吧 我是今天才知道有这家伙。
类型构造器,顾名思义,是一个类的类型的构造器(满绕的)。它定义为static并且访问级别只能是private。
类型构造器在类被第一次访问前调用,用来对类内部的静态成员进行初始化赋值(如果有的话),类内部的非静态成员在
类的构造器里面进行初始化。
例如:
public class SomeClass
{
Int32 i=0;//在类的构造器中进行初始化(.ctor)
static Int32 j=0;//在类型构造器中进行初始化(.cctor)
}
method private hidebysig specialname rtspecialname static void .cctor() cil managed
{//类型构造器
.maxstack 8
L_0000: ldc.i4.0 //将4封装入计算堆栈
L_0001: stsfld int32 CLR.SomeClass::j//替换j在栈中位置(从此以后4和j同居了?)
L_0006: ret
}
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.0
L_0002: stfld int32 CLR.SomeClass::i
L_0007: ldarg.0
L_0008: call instance void [mscorlib]System.Object::.ctor()//类的构造函数中会调用基类的构造函数。
L_000d: nop
L_000e: ret
}
并且,我们可以通过反编译得到,如果我们类中的静态变量没有进行初始化,那么在IL里面找不到相应的类型构造器。即
public class SomeClass
{在IL里面 找不到相应的.cctor()。
Int32 static j;
}
对于默认的类型构造器,JIT会进行优化,使它即时在同一个方法里都次调用也只需执行一次。
对于显示的类型构造器,JIT会在第一次调用它的方法里将它嵌入到方法的代码里。即如果在方法里用到了n次这个类型,那么就会调用n次的类型构造器。
用例子说明一切吧
(下面的例子来自"CLR via C#"第三版 清华大学出版社 周靖 译 第174-175页)
using System;
using System.Diagnostics;
internal class BeforeFieldInit
{
public static Int32 s_x=123;
}
class Precise
{
public static Int32 s_x;//木有赋值,所以编译的时候不检测是否有类型构造器。
static Precise(){s_x=123;}//注:如果木有这个东西,编译的时候Precise不会生成类型构造器
}
class Program()
{
const Int32 iterations = 2147483647;
PreTest1(iterations);
PreTest2(iterations);
Console.Read();
}
static void PreTest1(Int32 iterations)
{
Stopwatch sw = Stopwatch.StartNew();
for (Int32 x = 0; x < iterations; x++)
{
BeforeFieldInit.s_x = 1;
}
Console.WriteLine("P1:{0} BFI", sw.Elapsed);
sw = Stopwatch.StartNew();
for (Int32 x = 0; x < iterations; x++)
{
Presise.s_x = 1;
}
Console.WriteLine("P1:{0} Ps", sw.Elapsed);
}
static void PreTest2(Int32 iterations)
{
Stopwatch sw = Stopwatch.StartNew();
for (Int32 x = 0; x < iterations; x++)
{
BeforeFieldInit.s_x = 1;
}
Console.WriteLine("P1:{0} BFI", sw.Elapsed);
sw = Stopwatch.StartNew();
for (Int32 x = 0; x < iterations; x++)
{
Presise.s_x = 1;
}
Console.WriteLine("P1:{0} Ps", sw.Elapsed);
}
}
}
多次输出结果的都差不多:
把Precise的类型构造器注释后的运行结果如下:
最后,总结一句话,2^32次循环才节约大概4秒钟。还是升级下硬件设备实在。