コンパイラがクロージャの匿名メソッドで使用されるローカル変数をキャプチャすると、デリゲート定義を含むメソッドのスコープに固有のヘルパークラスが生成されます。そのスコープに複数の代理人がいる場合でも、スコープごとに1つのメソッドが存在します。 Eric Lippertの説明hereを参照してください。
.method public hidebysig static
void F() cil managed
{
// Method begins at RVA 0x205c
// Code size 56 (0x38)
.maxstack 2
.locals init (
[0] class ConsoleApplication.Program/'<>c__DisplayClass1_0' 'CS$<>8__locals0',
[1] class [mscorlib]System.Action a1,
[2] class [mscorlib]System.Action a2
)
IL_0000: newobj instance void ConsoleApplication.Program/'<>c__DisplayClass1_0'::.ctor()
IL_0005: stloc.0
IL_0006: nop
IL_0007: ldloc.0
IL_0008: newobj instance void [mscorlib]System.Random::.ctor()
IL_000d: stfld class [mscorlib]System.Random ConsoleApplication.Program/'<>c__DisplayClass1_0'::rnd1
IL_0012: ldloc.0
IL_0013: newobj instance void [mscorlib]System.Random::.ctor()
IL_0018: stfld class [mscorlib]System.Random ConsoleApplication.Program/'<>c__DisplayClass1_0'::rnd2
IL_001d: ldloc.0
IL_001e: ldftn instance void ConsoleApplication.Program/'<>c__DisplayClass1_0'::'<F>b__0'()
IL_0024: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0029: stloc.1
IL_002a: ldloc.0
IL_002b: ldftn instance void ConsoleApplication.Program/'<>c__DisplayClass1_0'::'<F>b__1'()
IL_0031: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0036: stloc.2
IL_0037: ret
} // end of method Program::F
注:私たちはF()
の実現のために以下を参照してくださいコンパイラによって生成されたILのための外観を撮影
using System;
namespace ConsoleApplication
{
internal class Program
{
private static void Main(string[] args)
{
F();
}
public static void F()
{
var rnd1 = new Random();
var rnd2 = new Random();
Action a1 =() => G(rnd1);
Action a2 =() => G(rnd2);
}
private static void G(Random r)
{
}
}
}
:あなたの例からの借入
は、次のプログラムを検討します最初のIL命令:IL_0000: newobj instance void ConsoleApplication.Program/'<>c__DisplayClass1_0'::.ctor()
コンパイラが生成したヘルパークラスのデフォルトコンストラクタを呼び出しています。これは、ローカル変数をキャプチャする責任を負うものですクローズのレこのヘルパークラスは、両方rnd1
とrnd2
のフィールドを持っていることを
.class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass1_0'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Fields
.field public class [mscorlib]System.Random rnd1
.field public class [mscorlib]System.Random rnd2
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Method begins at RVA 0x20a3
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method '<>c__DisplayClass1_0'::.ctor
.method assembly hidebysig
instance void '<F>b__0'() cil managed
{
// Method begins at RVA 0x20ac
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Random ConsoleApplication.Program/'<>c__DisplayClass1_0'::rnd1
IL_0006: call void ConsoleApplication.Program::G(class [mscorlib]System.Random)
IL_000b: nop
IL_000c: ret
} // end of method '<>c__DisplayClass1_0'::'<F>b__0'
.method assembly hidebysig
instance void '<F>b__1'() cil managed
{
// Method begins at RVA 0x20ba
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Random ConsoleApplication.Program/'<>c__DisplayClass1_0'::rnd2
IL_0006: call void ConsoleApplication.Program::G(class [mscorlib]System.Random)
IL_000b: nop
IL_000c: ret
} // end of method '<>c__DisplayClass1_0'::'<F>b__1'
} // end of class <>c__DisplayClass1_0
お知らせ:
はここで、コンパイラが生成するヘルパークラスのILです。 IL-レベルでF()
の
"最終" の実装は次のようである:
ClosureHelper
のに似実装さ
public static void F()
{
var closureHelper = new ClosureHelper();
closureHelper.rnd1 = new Random();
closureHelper.rnd2 = new Random();
Action a1 = closureHelper.MethodOne;
Action a2 = closureHelper.MethodTwo;
}
:ReSharperのはしない理由としては
internal class Program
{
public class ClosureHelper
{
public Random rnd1;
public Random rnd2;
void MethodOne()
{
Program.G(rnd1);
}
void MethodTwo()
{
Program.G(rnd2);
}
}
}
この場合暗黙のキャプチャが発生していることを警告します。わかりません。
出典
2016-04-13 21:11:46
AGB
私もその例は警告されていませんが、検査で暗黙のキャプチャが実際に発生していることが正しいことがわかりました(元のコードと回答のコードの両方) – dlf