Wie | Wo werden Closed-over-Variablen gespeichert?

8

Dies ist eine Frage, die auf dem Artikel " Schließen der Schleife Variable als schädlich "von Eric Lippert Es ist eine gute Lektüre, Eric erklärt, warum nach diesem Stück Code alle Funktionen den Wert last in v zurückgeben:

%Vor%

Und die richtige Version sieht so aus:

%Vor%

Nun meine Frage ist, wie und wo diese gefangenen 'v2' Variablen gespeichert sind. In meinem Verständnis des Stapels würden alle diese v2-Variablen das gleiche Stück Speicher belegen.

Mein erster Gedanke war das Boxen, wobei jedes Func-Mitglied einen Verweis auf eine Box-V2 behielt. Aber das würde den ersten Fall nicht erklären.

    
Henk Holterman 17.11.2009, 09:53
quelle

2 Antworten

6

Normalerweise würde die Variable v2 am Anfang des Codeblocks, in dem sie sich befindet, etwas Speicherplatz auf dem Stapel zugewiesen bekommen. Am Ende des Codeblocks (dh am Ende der Iteration) wird der Stapel zurückgespult (I Ich beschreibe das logische Szenario nicht als optimiertes tatsächliches Verhalten. Daher ist jedes v2 tatsächlich ein anderes v2 von der vorherigen Iteration, obwohl es zutrifft, dass es den gleichen Speicherplatz belegt.

Der Compiler erkennt jedoch, dass v2 von einer anonymen Funktion verwendet wird, die von Lambda erstellt wurde. Was der Compiler macht, ist hoist die Variable v2 . Der Compiler erstellt eine neue Klasse, die ein Int32-Feld enthält, um den Wert von v2 zu speichern, es ist kein Platz auf dem Stapel reserviert. Es macht auch die anonyme Funktion zu einer Methode dieses neuen Typs. (Der Einfachheit halber werde ich dieser nicht benannten Klasse einen Namen geben, nennen wir es "Sache").

Jetzt wird in jeder Iteration eine neue Instanz von "Thing" erstellt und wenn v2 zugewiesen ist, wird das Feld Int32 zugewiesen, das tatsächlich nicht nur einem Punkt in zugewiesen ist Stapelspeicher. Der anonyme Funktionsausdruck (das Lambda) gibt jetzt einen Delegaten zurück, der einen Verweis auf ein Nicht-Null-Instanzobjekt hat. Dieser Verweis bezieht sich auf die aktuelle Instanz von "Thing".

Wenn der Delegat für die anonyme Funktion aufgerufen wird, wird er als Instanzmethode einer "Thing" -Instanz ausgeführt. Daher ist v2 als Member-Feld verfügbar und hat den Wert, der während der Iteration, in der diese Instanz von "Thing" erstellt wurde, angegeben wurde.

    
AnthonyWJones 17.11.2009, 10:40
quelle
4

Neben den Antworten von Neil und Anthony ist hier ein Beispiel für den Code, der in beiden Fällen automatisch generiert werden könnte.

(Beachten Sie, dass dies nur zur Veranschaulichung des Prinzips gilt. Der vom Compiler generierte Code sieht nicht genau so aus. Wenn Sie den echten Code sehen möchten, können Sie sich den Reflector ansehen.)

%Vor%     
LukeH 17.11.2009 11:20
quelle

Tags und Links