asp.net C# 中的 static 关键字

作者:袖梨 2022-06-25

01:  ///


02:  /// 使用字节数组中的值初始 zipinteger 结构的新实例
03:  /// 注意:本构造函数会破坏传入的 bits 参数的值。
04:  ///

05:  /// 顺序为 big-endian 的字节值的数组
06:  public zipinteger(byte[] bits)
07:  {
08:    if (bits == null) throw new argumentnullexception("bits");
09:    if (bits.length < 1 || bits.length > 9) throw new argumentexception("invalid length", "bits");
10:    byte[] mask = { 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 };
11:    if (bits.length > 1 && bits.length < 9) bits[0] &= mask[bits.length - 1];
12:    array.reverse(bits);
13:    array.resize(ref bits, 8);
14:    if (!bitconverter.islittleendian) array.reverse(bits);
15:    data = decode(bitconverter.toint64(bits, 0));
16:  }


mask 数组其实只需要初始化一次就行了,而不需要每次调用该构造函数时都进行初始化。也就是说,应该将 mask 变量声明为 static 的,如下所示:

static readonly byte[] mask = { 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 };
愿望是美好的,现实是残酷的,加上 static 关键字后,再编译时 c# 编译器会报告以下错误:

error cs0106: 修饰符“static”对该项无效 
也就是说,c# 语言不允许使用 static 修饰符来声明方法内部的变量。但是在 c/c++ 语言中是允许这么做的。

如果把该构造函数内部的 mask 变量提升到构造函数外部,成为 zipinteger 结构的字段成员,就可以声明为 static 的。但是这样一样,读这段代码的人就不容易弄清楚 mask 字段只在这个构造函数内部使用,成为代码的“坏味道”,一点也不优雅了。

 

好了,让我们写一小段程序来测试一下加上 static 后对运行效率的影响:

01:  using system;
02:  using system.io;
03:  using system.diagnostics;
04:  using skyiv.numerics;
05: 
06:  namespace skyiv.tester
07:  {
08:    sealed class statictester
09:    {
10:      static void main()
11:      {
12:        try
13:        {
14:          new statictester().run(100000000);
15:        }
16:        catch (exception ex)
17:        {
18:          console.writeline(ex);
19:        }
20:      }
21: 
22:      void run(int count)
23:      {
24:        console.writeline("  os version: " + environment.osversion);
25:        console.writeline(" clr version: " + environment.version);
26:        using (var reader = new memorystream(getbytes(count)))
27:        {
28:          var watch = stopwatch.startnew();
29:          var n = 0;
30:          for (var i = 0; i < 10; i++)
31:          {
32:            reader.seek(0, seekorigin.begin);
33:            while (zipinteger.read(reader).hasvalue) n++;
34:          }
35:          watch.stop();
36:          console.writeline("       count: " + n.tostring("n0"));
37:          console.writeline("milliseconds: " + watch.elaps教程edmilliseconds.tostring("n0"));
38:        }
39:      }
40: 
41:      byte[] getbytes(int count)
42:      {
43:        var bits = new byte[count];
44:        var rand = new random(123456);
45:        rand.nextbytes(bits);
46:        return bits;
47:      }
48:    }
49:  }
上述程序中第 44 行使用固定的种子初始化 random 类的新实例,从而产生相同的随机数序列,以便用相同的测试用例来进行测试,使测试结果具有可比性。注意,在上述程序中如果 count 值和随机数的种子选取得不好,执行到第 33 行的 zipinteger.read 方法时是有可能抛出 endofstreamexception 异常的。

 

这个测试程序在 windows vista 操作系统的 .net framework 4 环境下的运行结果如下所示:

  os version: microsoft windows nt 6.0.6002 service pack 2
 clr version: 4.0.30319.1
       count: 500,990,730
milliseconds: 181,886

 
将这个测试程序对 mask 变量是非静态的和静态的两种情况分别运行五次,得到的 milliseconds 值如下表所示:

序号 非静态 静态
1 181,886 167,528
2 179,074 166,847
3 180,309 166,526
4 183,542 166,399
5 179,469 167,365
平均 180,856 166,933

经过简单的计算得知,静态情况下比非静态情况下的平均运行效率提高了 7.7%,还是很可观的。

 

这个测试程序在 ubuntu 10.10 操作系统的 mono 2.6.7 环境的运行结果如下所示:

非静态 静态
  os version: unix 2.6.35.24
 clr version: 2.0.50727.1433
       count: 500,992,030
milliseconds: 660,254

   os version: unix 2.6.35.24
 clr version: 2.0.50727.1433
       count: 500,992,030
milliseconds: 583,387

 

 

经过简单的计算得知,静态情况下比非静态情况下的运行效率提高了 11.6%,更是有了较大的改进。

 

我们来看看这两种情况下 c# 编译器生成的 il 代码,在非静态的情况下的该实例构造函数(.ctor)的 il 代码:

001:  .method public hidebysig specialname rtspecialname
002:          instance void  .ctor(uint8[] bits) cil managed
003:  {
004:    // 代码大小       181 (0xb5)
005:    .maxstack  5
006:    .locals init (uint8[] v_0,
007:             bool v_1)
008:    il_0000:  nop
009:    il_0001:  ldarg.1
010:    il_0002:  ldnull
011:    il_0003:  ceq
012:    il_0005:  ldc.i4.0
013:    il_0006:  ceq
014:    il_0008:  stloc.1
015:    il_0009:  ldloc.1
016:    il_000a:  brtrue.s   il_0017
017:    il_000c:  ldstr      "bits"
018:    il_0011:  newobj     instance void [mscorlib]system.argumentnullexception::.ctor(string)
019:    il_0016:  throw
020:    il_0017:  ldarg.1
021:    il_0018:  ldlen
022:    il_0019:  conv.i4
023:    il_001a:  ldc.i4.1
024:    il_001b:  blt.s      il_0029
025:    il_001d:  ldarg.1
026:    il_001e:  ldlen
027:    il_001f:  conv.i4
028:    il_0020:  ldc.i4.s   9
029:    il_0022:  cgt
030:    il_0024:  ldc.i4.0
031:    il_0025:  ceq
032:    il_0027:  br.s       il_002a
033:    il_0029:  ldc.i4.0
034:    il_002a:  stloc.1
035:    il_002b:  ldloc.1
036:    il_002c:  brtrue.s   il_003e
037:    il_002e:  ldstr      "invalid length"
038:    il_0033:  ldstr      "bits"
039:    il_0038:  newobj     instance void [mscorlib]system.argumentexception::.ctor(string,
040:                                                                                 string)
041:    il_003d:  throw
042:    il_003e:  ldc.i4.8
043:    il_003f:  newarr     [mscorlib]system.byte
044:    il_0044:  dup
045:    il_0045:  ldtoken    field int64 '
046:                           {78063cdc-e5ee-4c6b-a62d-fd0f919f6111}'::'$$method0x6000006-1'
047:    il_004a:  call       void [mscorlib]system.runtime.compilerservices.runtimehelpers::
048:                           initializearray(class [mscorlib]system.array,
049:                             valuetype [mscorlib]system.runtimefieldhandle)
050:    il_004f:  stloc.0
051:    il_0050:  ldarg.1
052:    il_0051:  ldlen
053:    il_0052:  conv.i4
054:    il_0053:  ldc.i4.1
055:    il_0054:  ble.s      il_0062
056:    il_0056:  ldarg.1
057:    il_0057:  ldlen
058:    il_0058:  conv.i4
059:    il_0059:  ldc.i4.s   9
060:    il_005b:  clt
061:    il_005d:  ldc.i4.0
062:    il_005e:  ceq
063:    il_0060:  br.s       il_0063
064:    il_0062:  ldc.i4.1
065:    il_0063:  stloc.1
066:    il_0064:  ldloc.1
067:    il_0065:  brtrue.s   il_0082
068:    il_0067:  ldarg.1
069:    il_0068:  ldc.i4.0
070:    il_0069:  ldelema    [mscorlib]system.byte
071:    il_006e:  dup
072:    il_006f:  ldobj      [mscorlib]system.byte
073:    il_0074:  ldloc.0
074:    il_0075:  ldarg.1
075:    il_0076:  ldlen
076:    il_0077:  conv.i4
077:    il_0078:  ldc.i4.1
078:    il_0079:  sub
079:    il_007a:  ldelem.u1
080:    il_007b:  and
081:    il_007c:  conv.u1
082:    il_007d:  stobj      [mscorlib]system.byte
083:    il_0082:  ldarg.1
084:    il_0083:  call       void [mscorlib]system.array::reverse(class [mscorlib]system.array)
085:    il_0088:  nop
086:    il_0089:  ldarga.s   bits
087:    il_008b:  ldc.i4.8
088:    il_008c:  call       void [mscorlib]system.array::resize(!!0[]&,
089:                                                                    int32)
090:    il_0091:  nop
091:    il_0092:  ldsfld     bool [mscorlib]system.bitconverter::islittleendian
092:    il_0097:  stloc.1
093:    il_0098:  ldloc.1
094:    il_0099:  brtrue.s   il_00a2
095:    il_009b:  ldarg.1
096:    il_009c:  call       void [mscorlib]system.array::reverse(class [mscorlib]system.array)
097:    il_00a1:  nop
098:    il_00a2:  ldarg.0
099:    il_00a3:  ldarg.1
100:    il_00a4:  ldc.i4.0
101:    il_00a5:  call       int64 [mscorlib]system.bitconverter::toint64(uint8[],
102:                                                                      int32)
103:    il_00aa:  call       int64 skyiv.numerics.zipinteger::decode(int64)
104:    il_00af:  stfld      int64 skyiv.numerics.zipinteger::data
105:    il_00b4:  ret
106:  } // end of method zipinteger::.ctor
上述 il 代码的第 42 行到第 49 行对 mask 数组进行初始化,紧接着在第 50 行用“stloc.0”指令保存起来,然后在第 73 行用“ldloc.0”指令引用。

 

再看看静态的情况下该实例构造函数(.ctor)的 il 代码:

01:  .method public hidebysig specialname rtspecialname
02:          instance void  .ctor(uint8[] bits) cil managed
03:  {
04:    // 代码大小       167 (0xa7)
05:    .maxstack  5
06:    .locals init (bool v_0)
07:    il_0000:  nop
08:    il_0001:  ldarg.1
09:    il_0002:  ldnull
10:    il_0003:  ceq
11:    il_0005:  ldc.i4.0
12:    il_0006:  ceq
13:    il_0008:  stloc.0
14:    il_0009:  ldloc.0
15:    il_000a:  brtrue.s   il_0017
16:    il_000c:  ldstr      "bits"
17:    il_0011:  newobj     instance void [mscorlib]system.argumentnullexception::.ctor(string)
18:    il_0016:  throw
19:    il_0017:  ldarg.1
20:    il_0018:  ldlen
21:    il_0019:  conv.i4
22:    il_001a:  ldc.i4.1
23:    il_001b:  blt.s      il_0029
24:    il_001d:  ldarg.1
25:    il_001e:  ldlen
26:    il_001f:  conv.i4
27:    il_0020:  ldc.i4.s   9
28:    il_0022:  cgt
29:    il_0024:  ldc.i4.0
30:    il_0025:  ceq
31:    il_0027:  br.s       il_002a
32:    il_0029:  ldc.i4.0
33:    il_002a:  stloc.0
34:    il_002b:  ldloc.0
35:    il_002c:  brtrue.s   il_003e
36:    il_002e:  ldstr      "invalid length"
37:    il_0033:  ldstr      "bits"
38:    il_0038:  newobj     instance void [mscorlib]system.argumentexception::.ctor(string,
39:                                                                                 string)
40:    il_003d:  throw
41:    il_003e:  ldarg.1
42:    il_003f:  ldlen
43:    il_0040:  conv.i4
44:    il_0041:  ldc.i4.1
45:    il_0042:  ble.s      il_0050
46:    il_0044:  ldarg.1
47:    il_0045:  ldlen
48:    il_0046:  conv.i4
49:    il_0047:  ldc.i4.s   9
50:    il_0049:  clt
51:    il_004b:  ldc.i4.0
52:    il_004c:  ceq
53:    il_004e:  br.s       il_0051
54:    il_0050:  ldc.i4.1
55:    il_0051:  stloc.0
56:    il_0052:  ldloc.0
57:    il_0053:  brtrue.s   il_0074
58:    il_0055:  ldarg.1
59:    il_0056:  ldc.i4.0
60:    il_0057:  ldelema    [mscorlib]system.byte
61:    il_005c:  dup
62:    il_005d:  ldobj      [mscorlib]system.byte
63:    il_0062:  ldsfld     uint8[] skyiv.numerics.zipinteger::mask
64:    il_0067:  ldarg.1
65:    il_0068:  ldlen
66:    il_0069:  conv.i4
67:    il_006a:  ldc.i4.1
68:    il_006b:  sub
69:    il_006c:  ldelem.u1
70:    il_006d:  and
71:    il_006e:  conv.u1
72:    il_006f:  stobj      [mscorlib]system.byte
73:    il_0074:  ldarg.1
74:    il_0075:  call       void [mscorlib]system.array::reverse(class [mscorlib]system.array)
75:    il_007a:  nop
76:    il_007b:  ldarga.s   bits
77:    il_007d:  ldc.i4.8
78:    il_007e:  call       void [mscorlib]system.array::resize(!!0[]&,
79:                                                                    int32)
80:    il_0083:  nop
81:    il_0084:  ldsfld     bool [mscorlib]system.bitconverter::islittleendian
82:    il_0089:  stloc.0
83:    il_008a:  ldloc.0
84:    il_008b:  brtrue.s   il_0094
85:    il_008d:  ldarg.1
86:    il_008e:  call       void [mscorlib]system.array::reverse(class [mscorlib]system.array)
87:    il_0093:  nop
88:    il_0094:  ldarg.0
89:    il_0095:  ldarg.1
90:    il_0096:  ldc.i4.0
91:    il_0097:  call       int64 [mscorlib]system.bitconverter::toint64(uint8[],
92:                                                                      int32)
93:    il_009c:  call       int64 skyiv.numerics.zipinteger::decode(int64)
94:    il_00a1:  stfld      int64 skyiv.numerics.zipinteger::data
95:    il_00a6:  ret
96:  } // end of method zipinteger::.ctor
上述 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 '
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

相关文章

精彩推荐