概要
ループ内で変数を宣言するために生成された IL と、ループ外で変数を宣言するために生成された IL を比較すると、2 つのスタイルの変数宣言の間にパフォーマンスの違いがないことが証明されます。(生成された IL は実質的に同一です。)
変数がループ内で宣言されているため、おそらく「より多くのリソース」を使用している元のソースは次のとおりです。
using System;
class A
{
public static void Main()
{
for (int i =0; i< 10; i++)
{
decimal? testDecimal;
string testString;
switch( i % 2 )
{
case 0:
testDecimal = i / ( decimal ).32;
testString = i.ToString();
break;
default:
testDecimal = null;
testString = null;
break;
}
Console.WriteLine( "Loop {0}: testDecimal={1} - testString={2}", i, testDecimal , testString );
}
}
}
非効率的な宣言ソースからの IL は次のとおりです。
.method public hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 8
.locals init (
[0] int32 num,
[1] valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal> nullable,
[2] string str,
[3] int32 num2,
[4] bool flag)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: br.s L_0061
L_0005: nop
L_0006: ldloc.0
L_0007: ldc.i4.2
L_0008: rem
L_0009: stloc.3
L_000a: ldloc.3
L_000b: ldc.i4.0
L_000c: beq.s L_0010
L_000e: br.s L_0038
L_0010: ldloca.s nullable
L_0012: ldloc.0
L_0013: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
L_0018: ldc.i4.s 0x20
L_001a: ldc.i4.0
L_001b: ldc.i4.0
L_001c: ldc.i4.0
L_001d: ldc.i4.2
L_001e: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32, int32, bool, uint8)
L_0023: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Division(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal)
L_0028: call instance void [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal>::.ctor(!0)
L_002d: nop
L_002e: ldloca.s num
L_0030: call instance string [mscorlib]System.Int32::ToString()
L_0035: stloc.2
L_0036: br.s L_0044
L_0038: ldloca.s nullable
L_003a: initobj [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal>
L_0040: ldnull
L_0041: stloc.2
L_0042: br.s L_0044
L_0044: ldstr "Loop {0}: testDecimal={1} - testString={2}"
L_0049: ldloc.0
L_004a: box int32
L_004f: ldloc.1
L_0050: box [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal>
L_0055: ldloc.2
L_0056: call void [mscorlib]System.Console::WriteLine(string, object, object, object)
L_005b: nop
L_005c: nop
L_005d: ldloc.0
L_005e: ldc.i4.1
L_005f: add
L_0060: stloc.0
L_0061: ldloc.0
L_0062: ldc.i4.s 10
L_0064: clt
L_0066: stloc.s flag
L_0068: ldloc.s flag
L_006a: brtrue.s L_0005
L_006c: ret
}
ループ外で変数を宣言するソースは次のとおりです。
using System;
class A
{
public static void Main()
{
decimal? testDecimal;
string testString;
for (int i =0; i< 10; i++)
{
switch( i % 2 )
{
case 0:
testDecimal = i / ( decimal ).32;
testString = i.ToString();
break;
default:
testDecimal = null;
testString = null;
break;
}
Console.WriteLine( "Loop {0}: testDecimal={1} - testString={2}", i, testDecimal , testString );
}
}
}
ループ外で変数を宣言する IL は次のとおりです。
.method public hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 8
.locals init (
[0] valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal> nullable,
[1] string str,
[2] int32 num,
[3] int32 num2,
[4] bool flag)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.2
L_0003: br.s L_0061
L_0005: nop
L_0006: ldloc.2
L_0007: ldc.i4.2
L_0008: rem
L_0009: stloc.3
L_000a: ldloc.3
L_000b: ldc.i4.0
L_000c: beq.s L_0010
L_000e: br.s L_0038
L_0010: ldloca.s nullable
L_0012: ldloc.2
L_0013: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Implicit(int32)
L_0018: ldc.i4.s 0x20
L_001a: ldc.i4.0
L_001b: ldc.i4.0
L_001c: ldc.i4.0
L_001d: ldc.i4.2
L_001e: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32, int32, bool, uint8)
L_0023: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Division(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal)
L_0028: call instance void [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal>::.ctor(!0)
L_002d: nop
L_002e: ldloca.s num
L_0030: call instance string [mscorlib]System.Int32::ToString()
L_0035: stloc.1
L_0036: br.s L_0044
L_0038: ldloca.s nullable
L_003a: initobj [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal>
L_0040: ldnull
L_0041: stloc.1
L_0042: br.s L_0044
L_0044: ldstr "Loop {0}: testDecimal={1} - testString={2}"
L_0049: ldloc.2
L_004a: box int32
L_004f: ldloc.0
L_0050: box [mscorlib]System.Nullable`1<valuetype [mscorlib]System.Decimal>
L_0055: ldloc.1
L_0056: call void [mscorlib]System.Console::WriteLine(string, object, object, object)
L_005b: nop
L_005c: nop
L_005d: ldloc.2
L_005e: ldc.i4.1
L_005f: add
L_0060: stloc.2
L_0061: ldloc.2
L_0062: ldc.i4.s 10
L_0064: clt
L_0066: stloc.s flag
L_0068: ldloc.s flag
L_006a: brtrue.s L_0005
L_006c: ret
}
秘密を共有します。.locals init ( ... )
指定されている順序を除いて、IL はまったく同じです。ループ内で変数を宣言すると、追加の IL は発生しません。