Was löst abschließend eine neue Instanz der erfassten Variablen aus?
Ich lese Jon SkeetsC # im Detail.
Auf Seite 175 finden Sie ein Beispiel in Listing 5.13, „Erfassen mehrerer Variableninstanzen mit mehreren Delegaten“.
List<ThreadStart> list = new List<ThreadStart>();
for(int index=0; index < 5; index++;)
{
int counter = index*10;
list.Add(delegate
{
Console.WriteLine(counter);
counter++;
}
);
}
foreach(ThreadStart t in list)
{
t();
}
list[0]();
list[0]();
list[0]();
list[1]();
In der Erklärung nach dieser Auflistung sagt er, dass "in diesem Fall jede der Stellvertreterinstanzen eine andere Variable erfasst hat".
Ich verstehe das gut genug, weil ich verstehe, dass der Compiler jedes Mal, wenn Sie eine Variable schließen, eine AWL generiert, die sie in eine neue Klasse einkapselt, die speziell dafür erstellt wurde, dass diese Variable erfasst werden kann (im Wesentlichen wird sie zu einem Referenztyp, sodass der Wert, auf den sie verweist to wird mit dem Stack-Frame des aktuell ausgeführten Scopes nicht zerstört).
Aber dann spricht er darüber, was passiert wäre, wenn wir gefangen genommen hättenindex
direkt anstatt die zu erstellencounter
Variable - "Alle Delegierten hätten dieselbe Variable geteilt".
Das verstehe ich nicht. Nichtindex
im gleichen Umfang wiecounter
? Warum sollte der Compiler nicht auch eine neue Instanz von erstellen?index
für jeden Teilnehmer?
Hinweis: Ich denke, ich habe es herausgefunden, als ich diese Frage getippt habe, aber ich werde die Frage hier für die Nachwelt belassen. Ich denke, die Antwort ist dasindex
ist eigentlich in einem anderen umfang alscounter
. Index wird im Wesentlichen als "außerhalb" der for-Schleife deklariert ... es ist jedes Mal dieselbe Variable.
Schauen Sie sich die IL an, die für a generiert wurdefor
Schleife, es beweist, dass die Variablen außerhalb der Schleife deklariert sind (length
undi
wurden Variablen in der deklariertfor
Schleifendeklaration).
.locals init (
[0] int32 length,
[1] int32 i,
[2] bool CSIch verstehe das gut genug, weil ich verstehe, dass der Compiler jedes Mal, wenn Sie eine Variable schließen, eine AWL generiert, die sie in eine neue Klasse einkapselt, die speziell dafür erstellt wurde, dass diese Variable erfasst werden kann (im Wesentlichen wird sie zu einem Referenztyp, sodass der Wert, auf den sie verweist to wird mit dem Stack-Frame des aktuell ausgeführten Scopes nicht zerstört).0000
)
IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: stloc.0
IL_0004: ldc.i4.0
IL_0005: stloc.1
IL_0006: br.s IL_001b
// loop start (head: IL_001b)
IL_0008: nop
IL_0009: ldloca.s i
IL_000b: call instance string [mscorlib]System.Int32::ToString()
IL_0010: call void [mscorlib]System.Console::WriteLine(string)
IL_0015: nop
IL_0016: nop
IL_0017: ldloc.1
IL_0018: ldc.i4.1
IL_0019: add
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: ldloc.0
IL_001d: clt
IL_001f: stloc.2
IL_0020: ldloc.2
IL_0021: brtrue.s IL_0008
// end loop
Eine Sache, die ich denke, dass das Buch in Bezug auf dieses Thema besser gemacht haben könnte, ist wirklich zu erklären, was der Compiler tut, denn all diese "Magie" ist sinnvoll, wenn Sie verstehen, dass der Compiler die über-geschlossene Variable in eine neue Klasse einhüllt.
Bitte korrigieren Sie eventuelle Missverständnisse. Fühlen Sie sich auch frei, näher darauf einzugehen und / oder meine Erklärung zu ergänzen.