技术开发 频道

详谈C# 语言中的 static 关键字

  上述 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

 

  可以看出,在上述 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

 

  我们知道,静态构造函数总共只执行一次,而实例构造函数在每次实例化时都要执行一行。也就是说,在我们的测试用例中,mask 数组在静态的情况下只要初始化一次,而在非静态的情况下要初始化 500,990,730 次。所以运行效率出现这么大的差别就很好理解了。

  除此之外,将方法内部的变量声明为 static 的,还可以起着方法内置状态的作用,这也是很有好处的。具体例子请参见“隐约有歌”大大的博文“技术面试题:f(f(n)) == -n”。

  综上所述,我强烈要求在 C# 5.0 中增加支持将方法内部的变量声明为 static 的。这在 C/C++ 语言中早就已经支持了,我想这应该不难实现,因为 Microsoft 的 C/C++ 也支持这一特性。

0