《详谈C语言中的static关键字》由会员分享,可在线阅读,更多相关《详谈C语言中的static关键字(11页珍藏版)》请在金锄头文库上搜索。
1、详谈C# 语言中的 static 关键字ZipInteger 结构中有以下构造函数: / / 使用字节数组中的值初始 ZipInteger 结构的新实例 / 注意:本构造函数会破坏传入的 bits 参数的值。 / / 顺序为 big-endian 的字节值的数组 public ZipInteger(byte bits) if (bits= null) thrownew ArgumentNullException(bits); if (bits.Length 9) thrownew ArgumentException(Invalid length,bits); byte mask= 0x7F,
2、0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00 ; if (bits.Length 1 & bits.Length 9) bits0&= maskbits.Length- 1; Array.Reverse(bits); Array.Resize(ref bits,8); if (!BitConverter.IsLittleEndian)Array.Reverse(bits); data= Decode(BitConverter.ToInt64(bits,0); 注意上述源程序第 10 行的 mask 数组其实只需要初始化一次就行了,而不需要每次调用该构造函数时
3、都进行初始化。也就是说,应该将 mask 变量声明为 static 的,如下所示:static readonlybyte mask= 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00 ; 愿望是美好的,现实是残酷的,加上 static 关键字后,再编译时 C# 编译器会报告以下错误:error CS0106: 修饰符“static”对该项无效 也就是说,C# 语言不允许使用 static 修饰符来声明方法内部的变量。但是在 C/C+ 语言中是允许这么做的。如果把该构造函数内部的 mask 变量提升到构造函数外部,成为 ZipInteger 结构的字段
4、成员,就可以声明为 static 的。但是这样一样,读这段代码的人就不容易弄清楚 mask 字段只在这个构造函数内部使用,成为代码的“坏味道”,一点也不优雅了。好了,让我们写一小段程序来测试一下加上 static 后对运行效率的影响: using System; using System.IO; using System.Diagnostics; using Skyiv.Numerics; namespace Skyiv.Tester sealed class StaticTester static void Main() try new StaticTester().Run(10000000
5、0); catch (Exception ex) Console.WriteLine(ex); void Run(int count) Console.WriteLine( OS Version: + Environment.OSVersion); Console.WriteLine( CLR Version: + Environment.Version); using (var reader= new MemoryStream(GetBytes(count) var watch= Stopwatch.StartNew(); var n= 0; for (var i= 0; i 10; i+)
6、 reader.Seek(0, SeekOrigin.Begin); while (ZipInteger.Read(reader).HasValue) n+; watch.Stop(); Console.WriteLine( Count: + n.ToString(N0); Console.WriteLine(Milliseconds: + watch.ElapsedMilliseconds.ToString(N0); byte GetBytes(int count) var bits= new bytecount; var rand= new Random(123456); rand.Nex
7、tBytes(bits); return bits; 上述程序中第 44 行使用固定的种子初始化 Random 类的新实例,从而产生相同的随机数序列,以便用相同的测试用例来进行测试,使测试结果具有可比性。注意,在上述程序中如果 count 值和随机数的种子选取得不好,执行到第 33 行的 ZipInteger.Read 方法时是有可能抛出 EndOfStreamException 异常的。这个测试程序在 Windows Vista 操作系统的 .NET Framework 4 环境下的运行结果如下所示:OS Version: Microsoft Windows NT6.0.6002 Servi
8、ce Pack2CLR Version:4.0.30319.1 Count:500,990,730Milliseconds:181,886 将这个测试程序对 mask 变量是非静态的和静态的两种情况分别运行五次,得到的 Milliseconds 值如下表所示: 经过简单的计算得知,静态情况下比非静态情况下的平均运行效率提高了 7.7%,还是很可观的。这个测试程序在 Ubuntu 10.10 操作系统的 mono 2.6.7 环境的运行结果如下所示: 经过简单的计算得知,静态情况下比非静态情况下的运行效率提高了 11.6%,更是有了较大的改进。我们来看看这两种情况下 C# 编译器生成的 IL 代
9、码,在非静态的情况下的该实例构造函数(.ctor)的 IL 代码:001: .methodpublic hidebysig specialname rtspecialname002: instance void .ctor(uint8 bits) cil managed003: 004: / 代码大小 181 (0xb5)005: .maxstack 5006: .locals init (uint8 V_0,007: bool V_1)008: IL_0000: nop009: IL_0001: ldarg.1010: IL_0002: ldnull011: IL_0003: ceq012:
10、 IL_0005: ldc.i4.0013: IL_0006: ceq014: IL_0008: stloc.1015: IL_0009: ldloc.1016: IL_000a: brtrue.s IL_0017017: IL_000c: ldstr bits018: IL_0011: newobj instance void mscorlibSystem.ArgumentNullException:.ctor(string)019: IL_0016: throw020: IL_0017: ldarg.1021: IL_0018: ldlen022: IL_0019: conv.i4023:
11、 IL_001a: ldc.i4.1024: IL_001b: blt.s IL_0029025: IL_001d: ldarg.1026: IL_001e: ldlen027: IL_001f: conv.i4028: IL_0020: ldc.i4.s 9029: IL_0022: cgt030: IL_0024: ldc.i4.0031: IL_0025: ceq032: IL_0027: br.s IL_002a033: IL_0029: ldc.i4.0034: IL_002a: stloc.1035: IL_002b: ldloc.1036: IL_002c: brtrue.s I
12、L_003e037: IL_002e: ldstr Invalid length038: IL_0033: ldstr bits039: IL_0038: newobj instance void mscorlibSystem.ArgumentException:.ctor(string,040: string)041: IL_003d: throw042: IL_003e: ldc.i4.8043: IL_003f: newarr mscorlibSystem.Byte044: IL_0044: dup045: IL_0045: ldtoken field int64046: 78063CDC-E5EE-4C6B-A62D-FD0F919F6111:$method0x6000006-1047: IL_004a: call void mscorlibSystem.Runtime.CompilerServices.RuntimeHelpers:048: InitializeArray(class mscor