Ich erhalte die folgende Warnung:
Zugriff auf jede Variable im Abschluss. Kann sich beim Kompilieren mit verschiedenen Compilerversionen unterschiedlich verhalten.
So sieht es in meinem Editor aus:
Ich weiß, wie diese Warnung behoben werden kann, aber ich möchte wissen, warum ich diese Warnung erhalten sollte.
Geht es um die "CLR" -Version? Hat es mit "IL" zu tun?
Antworten:
Diese Warnung besteht aus zwei Teilen. Das erste ist...
... was an sich nicht ungültig ist, aber auf den ersten Blick kontraintuitiv. Es ist auch sehr schwer, es richtig zu machen. (So sehr, dass der Artikel, auf den ich unten verweise, dies als "schädlich" beschreibt.)
Nehmen Sie Ihre Anfrage entgegen und stellen Sie fest, dass der Code, den Sie extrahiert haben, im Grunde eine erweiterte Form dessen ist, was der C # -Compiler (vor C # 5) für
foreach
1 generiert :Nun, es ist syntaktisch gültig. Und wenn Sie in Ihrer Schleife nur den Wert von verwenden,
s
ist alles gut. Das Schließens
führt jedoch zu einem kontraintuitiven Verhalten. Schauen Sie sich den folgenden Code an:Wenn Sie diesen Code ausführen, erhalten Sie die folgende Konsolenausgabe:
Das erwarten Sie.
Führen Sie den folgenden Code unmittelbar nach dem obigen Code aus, um etwas zu sehen, das Sie wahrscheinlich nicht erwarten :
Sie erhalten die folgende Konsolenausgabe:
Warum? Weil wir fünf Funktionen erstellt haben, die alle genau dasselbe tun: Drucken Sie den Wert von
s
(den wir geschlossen haben). In Wirklichkeit haben sie dieselbe Funktion ("Druckens
", "Druckens
", "Druckens
" ...).An dem Punkt, an dem wir sie verwenden, tun sie genau das, was wir verlangen: Drucken Sie den Wert von aus
s
. Wenn Sie sich den letzten bekannten Wert von ansehens
, werden Sie sehen, dass dies der Fall ist5
. Also werden wirs == 5
fünfmal auf die Konsole gedruckt.Welches ist genau das, wonach wir gefragt haben, aber wahrscheinlich nicht das, was wir wollen.
Der zweite Teil der Warnung ...
...es ist was es ist. Beginnend mit C # 5 generiert der Compiler einen anderen Code, der dies "verhindert"
foreach
.Daher führt der folgende Code unter verschiedenen Versionen des Compilers zu unterschiedlichen Ergebnissen:
Folglich wird auch die R # -Warnung ausgegeben :)
Mein erstes Code-Snippet oben zeigt in allen Versionen des Compilers das gleiche Verhalten, da ich es nicht verwende
foreach
(vielmehr habe ich es so erweitert, wie es Compiler vor C # 5 tun).Ich bin mir nicht ganz sicher, was Sie hier fragen.
Eric Lipperts Beitrag besagt, dass die Änderung "in C # 5" erfolgt. So
Vermutlich müssen Sie auf .NET 4.5 oder höher abzielenmit einem C # 5 oder höher Compiler, um das neue Verhalten zu erhalten, und alles davor bekommt das alte Verhalten.Es ist jedoch eine Funktion des Compilers und nicht der .NET Framework-Version.
Unterschiedlicher Code erzeugt unterschiedliche IL, sodass in diesem Sinne Konsequenzen für die generierte IL entstehen.
1
foreach
ist ein viel häufigeres Konstrukt als der Code, den Sie in Ihrem Kommentar gepostet haben. Das Problem tritt normalerweise durch die Verwendung vonforeach
und nicht durch manuelle Aufzählung auf. Aus diesem Grund verhindern die Änderungenforeach
in C # 5 dieses Problem, jedoch nicht vollständig.quelle
foreach
Zeug hier kommt aus dem Inhalt der Frage. Sie haben Recht, dass dies auf verschiedene, allgemeinere Arten geschehen kann.Die erste Antwort ist großartig, also dachte ich, ich würde nur eine Sache hinzufügen.
Sie erhalten die Warnung, weil in Ihrem Beispielcode ReflectedModel eine IEnumerable zugewiesen wird, die nur zum Zeitpunkt der Aufzählung ausgewertet wird, und die Aufzählung selbst außerhalb der Schleife erfolgen kann, wenn Sie ReflectModel etwas mit einem breiteren Bereich zugewiesen haben .
Wenn du dich verändert hast
...Where(x => x.Name == property.Value)
zu
...Where(x => x.Name == property.Value).ToList()
Dann würde ReflectedModel eine bestimmte Liste innerhalb der foreach-Schleife zugewiesen, sodass Sie die Warnung nicht erhalten würden, da die Aufzählung definitiv innerhalb der Schleife und nicht außerhalb der Schleife erfolgen würde.
quelle
Eine Variable mit Blockbereich sollte die Warnung auflösen.
quelle