C#のforeachの仕組み(5) ILにおけるforとの比較 int[]編

[C#のforeachの仕組み(4) ILにおけるforとの比較](https://qiita.com/y_ohr/items/1224eb74dbc82722faa0#_reference-5a2640548881c287fcbb) の続きです。

# 概要

[C#のforeachの仕組み(4) ILにおけるforとの比較](https://qiita.com/y_ohr/items/1224eb74dbc82722faa0#_reference-5a2640548881c287fcbb) の@NetSeed からのコメントより。

> T[]に対するfor/foreachもみてみると楽しいかも?

Let's try!

# コードとIL

forのコード。

``` antlr-csharp:Implement_array_for
using System;

namespace ConsoleAppArrayFor
{
    class Program
    {
        static void Main()
        {
            int[] numbers = { 0, 1, 2, 3, 4, 5, 6 };

            for (int i = 0; i < numbers.Length; i++)
            {
                Console.WriteLine(numbers[i]);
            }
        }
    }
}
```
forのIL。

```antlr:IL_array_for
.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // コード サイズ       49 (0x31)
  .maxstack  3
  .locals init (int32[] V_0,
           int32 V_1,
           bool V_2)
  IL_0000:  nop
  IL_0001:  ldc.i4.7
  IL_0002:  newarr     [System.Runtime]System.Int32
  IL_0007:  dup
  IL_0008:  ldtoken    field valuetype '<PrivateImplementationDetails>'/'__StaticArrayInitTypeSize=28' '<PrivateImplementationDetails>'::'50567A6578C37E24118E2B7EE8F5C7930666F62F'
  IL_000d:  call       void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [System.Runtime]System.Array,
                                                                                                            valuetype [System.Runtime]System.RuntimeFieldHandle)
  IL_0012:  stloc.0
  IL_0013:  ldc.i4.0
  IL_0014:  stloc.1
  IL_0015:  br.s       IL_0026
  IL_0017:  nop
  IL_0018:  ldloc.0
  IL_0019:  ldloc.1
  IL_001a:  ldelem.i4
  IL_001b:  call       void [System.Console]System.Console::WriteLine(int32)
  IL_0020:  nop
  IL_0021:  nop
  IL_0022:  ldloc.1
  IL_0023:  ldc.i4.1
  IL_0024:  add
  IL_0025:  stloc.1
  IL_0026:  ldloc.1
  IL_0027:  ldloc.0
  IL_0028:  ldlen
  IL_0029:  conv.i4
  IL_002a:  clt
  IL_002c:  stloc.2
  IL_002d:  ldloc.2
  IL_002e:  brtrue.s   IL_0017
  IL_0030:  ret
} // end of method Program::Main
```
foreachのコード。

``` antlr-csharp:Implement_array_foreach
using System;

namespace ConsoleAppArrayFor
{
    class Program
    {
        static void Main()
        {
            int[] numbers = { 0, 1, 2, 3, 4, 5, 6 };

            foreach (var n in numbers)
            {
                Console.WriteLine(n);
            }
        }
    }
}
```
foreachのIL。

```antlr:IL_array_foreach
.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // コード サイズ       50 (0x32)
  .maxstack  3
  .locals init (int32[] V_0,
           int32[] V_1,
           int32 V_2,
           int32 V_3)
  IL_0000:  nop
  IL_0001:  ldc.i4.7
  IL_0002:  newarr     [System.Runtime]System.Int32
  IL_0007:  dup
  IL_0008:  ldtoken    field valuetype '<PrivateImplementationDetails>'/'__StaticArrayInitTypeSize=28' '<PrivateImplementationDetails>'::'50567A6578C37E24118E2B7EE8F5C7930666F62F'
  IL_000d:  call       void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [System.Runtime]System.Array,
                                                                                                            valuetype [System.Runtime]System.RuntimeFieldHandle)
  IL_0012:  stloc.0
  IL_0013:  nop
  IL_0014:  ldloc.0
  IL_0015:  stloc.1
  IL_0016:  ldc.i4.0
  IL_0017:  stloc.2
  IL_0018:  br.s       IL_002b
  IL_001a:  ldloc.1
  IL_001b:  ldloc.2
  IL_001c:  ldelem.i4
  IL_001d:  stloc.3
  IL_001e:  nop
  IL_001f:  ldloc.3
  IL_0020:  call       void [System.Console]System.Console::WriteLine(int32)
  IL_0025:  nop
  IL_0026:  nop
  IL_0027:  ldloc.2
  IL_0028:  ldc.i4.1
  IL_0029:  add
  IL_002a:  stloc.2
  IL_002b:  ldloc.2
  IL_002c:  ldloc.1
  IL_002d:  ldlen
  IL_002e:  conv.i4
  IL_002f:  blt.s      IL_001a
  IL_0031:  ret
} // end of method Program::Main
```

# ILの相違点

```diff:diff_for_foreach_IL
@@ -1,11 +1,12 @@
 .method private hidebysig static void  Main() cil managed
 {
   .entrypoint
-  // コード サイズ       49 (0x31)
+  // コード サイズ       50 (0x32)
   .maxstack  3
   .locals init (int32[] V_0,
-           int32 V_1,
-           bool V_2)
+           int32[] V_1,
+           int32 V_2,
+           int32 V_3)
   IL_0000:  nop
   IL_0001:  ldc.i4.7
   IL_0002:  newarr     [System.Runtime]System.Int32
@@ -14,28 +15,30 @@
   IL_000d:  call       void [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [System.Runtime]System.Array,
                                                                                                             valuetype [System.Runtime]System.RuntimeFieldHandle)
   IL_0012:  stloc.0
-  IL_0013:  ldc.i4.0
-  IL_0014:  stloc.1
-  IL_0015:  br.s       IL_0026
-  IL_0017:  nop
-  IL_0018:  ldloc.0
-  IL_0019:  ldloc.1
-  IL_001a:  ldelem.i4
-  IL_001b:  call       void [System.Console]System.Console::WriteLine(int32)
-  IL_0020:  nop
-  IL_0021:  nop
-  IL_0022:  ldloc.1
-  IL_0023:  ldc.i4.1
-  IL_0024:  add
-  IL_0025:  stloc.1
-  IL_0026:  ldloc.1
-  IL_0027:  ldloc.0
-  IL_0028:  ldlen
-  IL_0029:  conv.i4
-  IL_002a:  clt
-  IL_002c:  stloc.2
-  IL_002d:  ldloc.2
-  IL_002e:  brtrue.s   IL_0017
-  IL_0030:  ret
+  IL_0013:  nop
+  IL_0014:  ldloc.0
+  IL_0015:  stloc.1
+  IL_0016:  ldc.i4.0
+  IL_0017:  stloc.2
+  IL_0018:  br.s       IL_002b
+  IL_001a:  ldloc.1
+  IL_001b:  ldloc.2
+  IL_001c:  ldelem.i4
+  IL_001d:  stloc.3
+  IL_001e:  nop
+  IL_001f:  ldloc.3
+  IL_0020:  call       void [System.Console]System.Console::WriteLine(int32)
+  IL_0025:  nop
+  IL_0026:  nop
+  IL_0027:  ldloc.2
+  IL_0028:  ldc.i4.1
+  IL_0029:  add
+  IL_002a:  stloc.2
+  IL_002b:  ldloc.2
+  IL_002c:  ldloc.1
+  IL_002d:  ldlen
+  IL_002e:  conv.i4
+  IL_002f:  blt.s      IL_001a
+  IL_0031:  ret
 } // end of method Program::Main
 ```

# まとめ

- foreachなのにGetEnumerator()もMoveNext()していない！
- int32[] V_1でforしている？
- foreachがforの糖衣構文みたいになっている？
- ステップ数も少ないしT[]の方が早そう