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?
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 .
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.
Kurze Antwort: Schließungen. Lange Antwort gegeben hier (unter anderem): unterschiedliches Verhalten wenn Einen Thread starten: ParameterizedThreadStart vs. Anonymous Delegate. Warum ist es wichtig?
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.
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
Tags und Links c#