C # Closures, warum wird die Schleifenvariable durch Referenz erfasst?

8

In diesem Beispiel versuche ich, den Wert zu übergeben, aber die Referenz wird stattdessen übergeben.

%Vor%

Dies kann wie folgt behoben werden:

%Vor%

Was ist hier los? Warum übergibt das ursprüngliche Beispiel die Referenz?

    
Henk Holterman 18.12.2009, 19:10
quelle

6 Antworten

16

Nun, so funktioniert C #. Der Lambda-Ausdruck in Ihrer Anweisung erstellt einen lexikalischen Abschluss, der einen einzelnen Verweis auf i speichert, der auch nach Abschluss der Schleife bestehen bleibt.

Um es zu beheben, können Sie genau das tun, was Sie getan haben.

Fühlen Sie sich frei, mehr zu diesem speziellen Thema im Internet zu lesen. Meine Entscheidung wäre Eric Lipperts Diskussion hier .

    
mquander 18.12.2009, 19:13
quelle
16

Dies ist einfacher zu verstehen, wenn Sie sich ansehen, was im Hinblick auf den Umfang passiert:

%Vor%

Im Grunde bedeutet das etwas sehr nahes:

%Vor%

Wenn Sie einen Lambda-Ausdruck verwenden und eine außerhalb von Lambda deklarierte Variable verwenden (in Ihrem Fall i ), erstellt der Compiler eine sogenannte Closure - eine temporäre Klasse, die die i-Variable nach oben und "umschließt" stellt es dem Delegaten zur Verfügung, der von Lambda generiert wurde.

Die Schließung ist auf der gleichen Ebene wie die Variable (i) aufgebaut, also in Ihrem Fall:

%Vor%

Aus diesem Grund wird jedem Thread der selbe Abschluss zugewiesen.

Wenn Sie Ihre Schleife so bearbeiten, dass sie ein temporäres verwendet, wird die Schließung stattdessen auf dieser Ebene generiert:

%Vor%

Nun erhält jeder Thread seine eigene Instanz und alles funktioniert einwandfrei.

    
Reed Copsey 18.12.2009 19:19
quelle
3
2

Sie möchten auf jeden Fall Eric Lipperts "Schließen über die Schleifenvariable als schädlich" lesen:

Kurz gesagt: Das Verhalten, das Sie sehen, ist genau, wie C # funktioniert.

    
Michael Stum 18.12.2009 19:15
quelle
1

Das passiert, weil C # Parameter an Lambda weiterleitet. Sie umschließt den Variablenzugriff in einer Klasse, die während der Kompilierung erstellt wird, und legt sie als Feld für den Lambda-Text offen.

    
codekaizen 18.12.2009 19:15
quelle
0

Bei Verwendung eines anonymen Delegaten oder eines Lambda-Ausdrucks wird eine Sperrung erstellt, sodass auf externe Variablen verwiesen werden kann . Wenn der Abschluss erstellt wird, werden die Variablen stack (value) zum Heap heraufgestuft.

Eine Möglichkeit, dies zu vermeiden, besteht darin, den Thread mit einem ParameterizedThreadStart-Delegat zu starten. E.G .:

%Vor%

Zufälligerweise bin ich erst gestern auf dieses Konzept gestoßen: Link

    
Matthew Sposato 18.12.2009 19:23
quelle

Tags und Links