Der einfachste Weg, um herauszufinden, wie es umgesetzt wird, ist, es auszuprobieren. Schreiben Sie einen Code, der eine erfasste Variable verwendet, kompilieren Sie ihn, und schauen Sie ihn sich dann in Reflektor . Beachten Sie, dass es sich um die variable die erfasst wird, und nicht die Wert . Das ist einer der großen Unterschiede zwischen Java und C# in diesem Bereich.
Die Grundidee ist, dass jede Ebene des Geltungsbereichs, die mindestens eine erfasste Variable enthält, zu einer neuen Klasse mit Feldern für die erfassten Variablen führt. Wenn es mehr als eine Ebene gibt, hat ein innerer Bereich auch ein Feld für den nächsthöheren Bereich und so weiter. Die echten lokalen Variablen auf dem Stack sind schließlich 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 erhalten andere Ergebnisse, wenn Sie keine Kopie nehmen - experimentieren Sie!) Dies wird wie folgt in Code übersetzt:
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);
}
}
}
Alle Der Verweis auf die erfasste Variable geht schließlich durch die Instanz der generierten Klasse, es handelt sich also nicht nur um eine einmalige Kopie. (Okay, in diesem Fall verwendet nichts anderes im Code die erfassten Variablen, aber Sie können sich leicht vorstellen, dass das möglich ist). Beachten Sie, dass bei jeder Iteration der äußeren Schleife die fünf neuen Instanzen sich alle eine Instanz von OuterScope
. Sie könnten versuchen, mit zusätzlichem Code im Delegaten zu spielen, um zu sehen, wie sich das auswirkt - wenn der Delegat sich ändert copyofI
diese Änderung wird im nächsten Delegierten sichtbar; Änderungen an copyOfJ
wird nicht gesehen, weil der nächste Delegierte eine separate Instanz von InnerScope
.