Update: um zu sehen, was ohne tatsächlich geschieht auf IL zurückgreifen: Using reflector to understand anonymous methods and captured variables
Wenn Sie:
public Bar CreateBar()
{
return new Bar(x,() => y);
}
Sie implizit this.y
sind Sinn; so in Bezug auf den Delegierten, ist es die Referenz zu Foo
, die enthalten ist. Als solche behält die Instanz Bar
(über den Delegierten) die gesamte Foo
am Leben (nicht Müll gesammelt), bis die Bar
zur Sammlung verfügbar ist.
Insbesondere (in diesem Fall) ist es nicht notwendig, dass der Compiler eine zusätzliche Klasse zur Verarbeitung der erfassten Variablen generiert; Das einzige Erforderliche ist die Foo
-Instanz, so dass eine Methode unter Foo
generiert werden kann. Dies wäre komplexer, wenn der Delegierte lokale Variablen (außer this
) involviert.
In Bezug auf die Serialisierung ... nun, das erste, was ich sagen würde ist, dass die Serialisierung von Delegierten eine sehr sehr schlechte Idee ist. Allerdings BinaryFormatter
wird Spaziergang Delegierten, und Sie können (in der Theorie) am Ende mit einem serialisierten Bar
, eine serialisierte Foo
und eine serialisierte delegieren sie zu verbinden - aber nur wenn Sie Foo
als [Serializable]
markieren.
Aber ich betone - das ist eine schlechte Idee. Ich verwende selten BinaryFormatter
(aus einer Vielzahl von Gründen), aber eine häufige Frage, die ich von Leuten sehe, die es verwenden, ist "warum versucht es zu serialisieren (irgendein zufälliger Typ)". Normalerweise lautet die Antwort: "Sie veröffentlichen ein Ereignis und versuchen, den Abonnenten zu serialisieren". In diesem Fall würde das am häufigsten anzutreffende Problem darin bestehen, das Feld des Ereignisses als [NonSerialized]
zu markieren.
Anstatt IL zu betrachten; Eine andere Möglichkeit, dies zu untersuchen, ist die Verwendung von Reflector im .NET 1.0-Modus (d. h. ohne dass anonyme Methoden ausgetauscht werden). dann können Sie sehen:
public Bar CreateBar()
{
return new Bar(this.x, new Func<int>(this.<CreateBar>b__0));
}
[CompilerGenerated]
private int <CreateBar>b__0()
{
return this.y;
}
Wie Sie sehen können; Das an Bar
übergebene Objekt ist ein Delegierter für eine verborgene Methode (<CreateBar>b__0()
) in der aktuellen Instanz (this
). So ist es ist die Instanz der aktuellen Foo
, die an die Bar
übergeben wird.
In Abschnitt 6.5.3 der C# -Programmiersprache (3. Ausgabe) gibt es ein Beispiel, das diesem Fall sehr ähnlich ist und genauso behandelt wird, wie Marc durch eine vom Compiler erzeugte Instanzmethode auf Foo erklärt wurde. –
Fantastische Antwort Marc! Vielen Dank! –