Der einfachste Weg zu finden, wie es umgesetzt ist, ist es zu versuchen. Schreiben Sie einen Code, der eine erfasste Variable verwendet, kompilieren Sie sie und betrachten Sie sie dann in Reflector. Beachten Sie, dass es die Variable ist, die erfasst wird, nicht die Wert. Das ist einer der großen Unterschiede zwischen Java und C# in diesem Bereich.
Die Grundidee ist, dass jede Ebene des Bereichs, die mindestens eine erfasste Variable enthält, zu einer neuen Klasse mit Feldern für die Variablen führt, die erfasst wurden. Wenn es mehr als eine Ebene gibt, hat ein innerer Bereich auch ein Feld für den nächsten Bereich und so weiter. Die echten lokalen Variablen im Stapel sind Verweise auf Instanzen der automatisch generierten Klassen.
Hier ist ein Beispiel:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Action> actions = new List<Action>();
for (int i=0; i < 5; i++)
{
int copyOfI = i;
for (int j=0; j < 5; j++)
{
int copyOfJ = j;
actions.Add(delegate
{
Console.WriteLine("{0} {1}", copyOfI, copyOfJ);
});
}
}
foreach (Action action in actions)
{
action();
}
}
}
(Sie unterschiedliche Ergebnisse erhalten, wenn Sie nicht über eine Kopie natürlich nehmen - Experiment!) Diese in Code wie folgt zusammengestellt:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Action> actions = new List<Action>();
for (int i=0; i < 5; i++)
{
OuterScope outer = new OuterScope();
outer.copyOfI = i;
for (int j=0; j < 5; j++)
{
InnerScope inner = new InnerScope();
inner.outer = outer;
inner.copyOfJ = j;
actions.Add(inner.Action);
}
}
foreach (Action action in actions)
{
action();
}
}
class OuterScope
{
public int copyOfI;
}
class InnerScope
{
public int copyOfJ;
public OuterScope outer;
public void Action()
{
Console.WriteLine("{0} {1}", outer.copyOfI, copyOfJ);
}
}
}
Jeder Verweis auf die erfasste Variable endet durch die Instanz der generierten Klasse, also ist es nicht nur eine einmalige Kopie. (Okay, in diesem Fall verwendet nichts anderes im Code die erfassten Variablen, aber Sie können es sich leicht vorstellen.) Beachten Sie, dass für jede Iteration der äußeren Schleife die fünf neuen Instanzen alle eine Instanz von OuterScope
gemeinsam haben. Sie können versuchen, mit zusätzlichen Code im Delegaten zu spielen, um zu sehen, wie sich das auf Dinge auswirkt - wenn der Delegat copyofI
ändert, wird diese Änderung im nächsten Delegaten angezeigt; Änderungen an werden nicht angezeigt, da der nächste Delegat eine separate Instanz InnerScope
verwendet.
Hallo, sehr schöne Erklärung. Sie können auch anzeigen, was der Compiler ohne das Kopieren auf lokale Variable produzieren würde. –