通过MSIL看foreach循环

static void Main(string[] args)
{
    string[] names = new string[] { "zhang", "li", "wang" };
    foreach (string name in names)
        Console.WriteLine(name);

    Console.ReadKey();
}

对应的MSIL代码为:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       80 (0x50)
  .maxstack  3
  .locals init ([0] string[] names,
           [1] string name,
           [2] string[] CS$0$0000,
           [3] string[] CS$6$0001,
           [4] int32 CS$7$0002,
           [5] bool CS$4$0003)
  IL_0000:  nop
  IL_0001:  ldc.i4.3
  IL_0002:  newarr     [mscorlib]System.String
  IL_0007:  stloc.2
  IL_0008:  ldloc.2
  IL_0009:  ldc.i4.0
  IL_000a:  ldstr      "zhang"
  IL_000f:  stelem.ref
  IL_0010:  ldloc.2
  IL_0011:  ldc.i4.1
  IL_0012:  ldstr      "li"
  IL_0017:  stelem.ref
  IL_0018:  ldloc.2
  IL_0019:  ldc.i4.2
  IL_001a:  ldstr      "wang"
  IL_001f:  stelem.ref
  IL_0020:  ldloc.2
  IL_0021:  stloc.0
  IL_0022:  nop
  IL_0023:  ldloc.0
  IL_0024:  stloc.3
  IL_0025:  ldc.i4.0
  IL_0026:  stloc.s    CS$7$0002
  IL_0028:  br.s       IL_003c
  IL_002a:  ldloc.3
  IL_002b:  ldloc.s    CS$7$0002
  IL_002d:  ldelem.ref
  IL_002e:  stloc.1
  IL_002f:  ldloc.1
  IL_0030:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0035:  nop
  IL_0036:  ldloc.s    CS$7$0002
  IL_0038:  ldc.i4.1
  IL_0039:  add
  IL_003a:  stloc.s    CS$7$0002
  IL_003c:  ldloc.s    CS$7$0002
  IL_003e:  ldloc.3
  IL_003f:  ldlen
  IL_0040:  conv.i4
  IL_0041:  clt
  IL_0043:  stloc.s    CS$4$0003
  IL_0045:  ldloc.s    CS$4$0003
  IL_0047:  brtrue.s   IL_002a
  IL_0049:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_004e:  pop
  IL_004f:  ret
} // end of method Program::Main


下边我们做些简单的分析

.locals init ([0] string[] names,
       [1] string name,
       [2] string[] CS$0$0000,
       [3] string[] CS$6$0001,
       [4] int32 CS$7$0002,
       [5] bool CS$4$0003)

我们在C#代码中只声明了两个局部变量names和name,但在MSIL中多出了4个。

IL_0000:  nop
IL_0001:  ldc.i4.3
IL_0002:  newarr     [mscorlib]System.String
IL_0007:  stloc.2
IL_0008:  ldloc.2
IL_0009:  ldc.i4.0
IL_000a:  ldstr      "zhang"
IL_000f:  stelem.ref
IL_0010:  ldloc.2
IL_0011:  ldc.i4.1
IL_0012:  ldstr      "li"
IL_0017:  stelem.ref
IL_0018:  ldloc.2
IL_0019:  ldc.i4.2
IL_001a:  ldstr      "wang"
IL_001f:  stelem.ref
IL_0020:  ldloc.2
IL_0021:  stloc.0

可以看到,MSIL先创建辅助字符串数组CS$0$0000,分配各元素的值,然后赋值给我们的names数组,感觉是转了一圈间接的来创建names数组,不知有什么优点?

IL_0022:  nop
IL_0023:  ldloc.0
IL_0024:  stloc.3
IL_0025:  ldc.i4.0
IL_0026:  stloc.s    CS$7$0002
IL_0028:  br.s       IL_003c
IL_002a:  ldloc.3
IL_002b:  ldloc.s    CS$7$0002
IL_002d:  ldelem.ref
IL_002e:  stloc.1
IL_002f:  ldloc.1
IL_0030:  call       void [mscorlib]System.Console::WriteLine(string)
IL_0035:  nop
IL_0036:  ldloc.s    CS$7$0002
IL_0038:  ldc.i4.1
IL_0039:  add
IL_003a:  stloc.s    CS$7$0002
IL_003c:  ldloc.s    CS$7$0002
IL_003e:  ldloc.3
IL_003f:  ldlen
IL_0040:  conv.i4
IL_0041:  clt
IL_0043:  stloc.s    CS$4$0003
IL_0045:  ldloc.s    CS$4$0003
IL_0047:  brtrue.s   IL_002a

从这段代码可以看出,foreach循环的内部其实是使用了for循环,CS$7$0002变量就相当于我们for循环中的i。让人困惑的是,这边操作的字符串数组即非CS$0$0000,也非names,又弄了个新数组CS$6$0001来用于循环,实在不解。

结论

在C#中,foreach循环的内部还是使用for循环。

评论: 0 | 引用: 0 | 查看次数: 3812
发表评论
登录后再发表评论!