上述 IL 代码中就没有对 mask 数组进行初始化,而是在第 63 行用“ldsfld”指令直接引用 ZipInteger 结构的静态字段,即已经初始化好了的 mask 数组。这个 mask 数组是在 ZipInteger 结构的静态构造函数(.cctor)中初始化的,如下所示:
01: .method private hidebysig specialname rtspecialname static
02: void .cctor() cil managed
03: {
04: // 代码大小 61 (0x3d)
05: .maxstack 8
06: IL_0000: ldc.i8 0x8000000000000000
07: IL_0009: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
08: IL_000e: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MinValue
09: IL_0013: ldc.i8 0x7fffffffffffffff
10: IL_001c: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
11: IL_0021: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MaxValue
12: IL_0026: ldc.i4.8
13: IL_0027: newarr [mscorlib]System.Byte
14: IL_002c: dup
15: IL_002d: ldtoken field int64 '<PrivateImplementationDetails>
16: {CDCDEB38-994E-4730-8D14-55B1DBDE4B1B}'::'$$method0x6000016-1'
17: IL_0032: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::
18: InitializeArray(class [mscorlib]System.Array,
19: valuetype [mscorlib]System.RuntimeFieldHandle)
20: IL_0037: stsfld uint8[] Skyiv.Numerics.ZipInteger::mask
21: IL_003c: ret
22: } // end of method ZipInteger::.cctor
02: void .cctor() cil managed
03: {
04: // 代码大小 61 (0x3d)
05: .maxstack 8
06: IL_0000: ldc.i8 0x8000000000000000
07: IL_0009: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
08: IL_000e: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MinValue
09: IL_0013: ldc.i8 0x7fffffffffffffff
10: IL_001c: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
11: IL_0021: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MaxValue
12: IL_0026: ldc.i4.8
13: IL_0027: newarr [mscorlib]System.Byte
14: IL_002c: dup
15: IL_002d: ldtoken field int64 '<PrivateImplementationDetails>
16: {CDCDEB38-994E-4730-8D14-55B1DBDE4B1B}'::'$$method0x6000016-1'
17: IL_0032: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::
18: InitializeArray(class [mscorlib]System.Array,
19: valuetype [mscorlib]System.RuntimeFieldHandle)
20: IL_0037: stsfld uint8[] Skyiv.Numerics.ZipInteger::mask
21: IL_003c: ret
22: } // end of method ZipInteger::.cctor
可以看出,在上述 IL 代码中的第 12 到第 20 行对静态的 mask 数组进行了初始化。
相对应的非静态情况下的 ZipInteger 结构的静态构造函数(.cctor)就没有对 mask 数组进行初始化的语句:
01: .method private hidebysig specialname rtspecialname static
02: void .cctor() cil managed
03: {
04: // 代码大小 39 (0x27)
05: .maxstack 8
06: IL_0000: ldc.i8 0x8000000000000000
07: IL_0009: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
08: IL_000e: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MinValue
09: IL_0013: ldc.i8 0x7fffffffffffffff
10: IL_001c: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
11: IL_0021: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MaxValue
12: IL_0026: ret
13: } // end of method ZipInteger::.cctor
02: void .cctor() cil managed
03: {
04: // 代码大小 39 (0x27)
05: .maxstack 8
06: IL_0000: ldc.i8 0x8000000000000000
07: IL_0009: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
08: IL_000e: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MinValue
09: IL_0013: ldc.i8 0x7fffffffffffffff
10: IL_001c: call valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::op_Implicit(int64)
11: IL_0021: stsfld valuetype Skyiv.Numerics.ZipInteger Skyiv.Numerics.ZipInteger::MaxValue
12: IL_0026: ret
13: } // end of method ZipInteger::.cctor
我们知道,静态构造函数总共只执行一次,而实例构造函数在每次实例化时都要执行一行。也就是说,在我们的测试用例中,mask 数组在静态的情况下只要初始化一次,而在非静态的情况下要初始化 500,990,730 次。所以运行效率出现这么大的差别就很好理解了。
除此之外,将方法内部的变量声明为 static 的,还可以起着方法内置状态的作用,这也是很有好处的。具体例子请参见“隐约有歌”大大的博文“技术面试题:f(f(n)) == -n”。
综上所述,我强烈要求在 C# 5.0 中增加支持将方法内部的变量声明为 static 的。这在 C/C++ 语言中早就已经支持了,我想这应该不难实现,因为 Microsoft 的 C/C++ 也支持这一特性。