C#のforeachの仕組み(4) ILにおけるforとの比較 の続きです。
概要
C#のforeachの仕組み(4) ILにおけるforとの比較 の@NetSeed からのコメントより。
T[]に対するfor/foreachもみてみると楽しいかも?
Let's try!
コードとIL
forのコード。
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。
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のコード。
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。
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_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[]の方が早そう