grałem z delegates
i zauważyłem, że gdy tworzę Func<int,int,int>
jak w poniższym przykładzie:Dlaczego kompilator dodaje dodatkowy parametr dla delegatów, gdy nie ma zamknięcia?
Func<int, int, int> func1 = (x, y) => x * y;
Podpis metody kompilatora generowany jest czego się spodziewałem:
jako widać, że pobiera obiekt dla pierwszego parametru. Ale kiedy jest zamknięcie:
int z = 10;
Func<int, int, int> func1 = (x, y) => x * y * z;
Everthing działa zgodnie z oczekiwaniami:
ten kod IL dla metody z dodatkowym parametrem:
.method private hidebysig static int32 '<Main>b__0'(object A_0,
int32 x,
int32 y) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (01 00 00 00)
// Code size 8 (0x8)
.maxstack 2
.locals init ([0] int32 V_0)
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: mul
IL_0003: stloc.0
IL_0004: br.s IL_0006
IL_0006: ldloc.0
IL_0007: ret
} // end of method Program::'<Main>b__0'
Wydaje się, że parametr A_0
nie jest jeszcze używany. Więc jaki jest cel parametru object
w pierwszym przypadku? Dlaczego nie jest dodawany, gdy istnieje zamknięcie?
Uwaga: Jeśli masz lepszy pomysł na tytuł, możesz edytować.
Uwaga 2: Pierwszy skompilowany kod w trybach Debug
i Release
, nie było różnicy. Ale skompilowałem drugi tryb w trybie Debug
, aby uzyskać zachowanie zamknięcia, ponieważ optymalizuje on zmienną lokalną w trybie Release
.
Uwaga 3: Używam Visual Studio 2014 CTP
.
Edit: Jest to kod wygenerowany dla Main
w pierwszym przypadku:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 30 (0x1e)
.maxstack 2
.locals init ([0] class [mscorlib]System.Func`3<int32,int32,int32> func1)
IL_0000: nop
IL_0001: ldsfld class [mscorlib]System.Func`3<int32,int32,int32> ConsoleApplication9.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0006: dup
IL_0007: brtrue.s IL_001c
IL_0009: pop
IL_000a: ldnull
IL_000b: ldftn int32 ConsoleApplication9.Program::'<Main>b__0'(object,
int32,
int32)
IL_0011: newobj instance void class [mscorlib]System.Func`3<int32,int32,int32>::.ctor(object,
native int)
IL_0016: dup
IL_0017: stsfld class [mscorlib]System.Func`3<int32,int32,int32> ConsoleApplication9.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_001c: stloc.0
IL_001d: ret
} // end of method Program::Main
Kiedy to nazwiesz, co zostanie przekazane? – siride
@side w kodzie, wszystko działa zgodnie z oczekiwaniami. Nie widzę żadnego dodatkowego parametru w sygnaturze 'func' podczas wywoływania go. –
Jeśli rzeczywiście istnieje parametr obiektu, to po wywołaniu lambda coś powinno zostać przekazane w tym gnieździe. Powinien przynajmniej pojawić się w IL. To tam powinieneś patrzeć. – siride