2008-10-22 6 views
48

Ich habe nur ein paar schnelle Schreiben von Code und bemerkte dieses complier FehlerWarum ist es schlecht eine Iterationsvariable in einem Lambda-Ausdruck zu verwenden

die Iterationsvariable in einem Lambda-Ausdruck verwenden, kann zu unerwarteten Ergebnissen führen.
Erstellen Sie stattdessen eine lokale Variable innerhalb der Schleife und weisen Sie ihr den Wert der Iterationsvariablen zu.

Ich weiß, was es bedeutet, und ich kann es leicht beheben, keine große Sache.
Aber ich fragte mich, warum es eine schlechte Idee ist, eine Iterationsvariable in einem Lambda zu verwenden?
Welche Probleme kann ich später verursachen?

+0

bezogen: http://stackoverflow.com/questions/190227/building-a-linq-query-programatical-without-local-variables-tricking-me – nawfal

+0

besser, wenn Sie ein Beispiel geben, wo es tatsächlich funktioniert/gibt die richtiges Ergebnis! zB schau dir das Ergebnis hier an http://pastebin.com/raw/FghmXkby ist es nicht richtig .. immer das gleiche falsche Ergebnis. – barlop

Antwort

50

Cons Diesen Code einbetten:

List<Action> actions = new List<Action>(); 

for (int i=0; i < 10; i++) 
{ 
    actions.Add(() => Console.WriteLine(i)); 
} 

foreach (Action action in actions) 
{ 
    action(); 
} 

Was würden Sie von diesem Drucker erwarten? Die offensichtliche Antwort ist 0 ... 9 - aber tatsächlich druckt es 10, 10 mal. Das liegt daran, dass nur eine Variable von allen Delegierten erfasst wird. Es ist diese Art von Verhalten, die unerwartet ist.

EDIT: Ich habe gerade gesehen, dass Sie über VB.NET sprechen, anstatt C#. Ich glaube, dass VB.NET noch kompliziertere Regeln hat, aufgrund der Art, wie Variablen ihre Werte über Iterationen hinweg beibehalten. This post by Jared Parsons gibt einige Informationen über die Art der Schwierigkeiten - obwohl es von 2007 zurück ist, so hat sich das tatsächliche Verhalten seit damals möglicherweise geändert.

+6

In zwei Worten: Lambda werden nicht notwendigerweise während der Schleife ausgewertet, und wenn sie aufgerufen werden, kann die Iterationsvariable außerhalb des Gültigkeitsbereichs, nicht zugewiesen oder mit ihrem endgültigen Wert liegen (sogar über das Schleifenlimit hinaus). – BertuPG

+8

@BertuPG: An welche der beiden Wörter hast du gedacht? ;) –

+0

@Joh: oh ... yeah ... also lass mich "Wörter" durch "Sätze" ersetzen ^^ – BertuPG

6

Angenommen, Sie meinen C# hier.

Es ist wegen der Art, wie der Compiler Closures implementiert. Die Verwendung einer Iterationsvariablen kann verursachen ein Problem mit dem Zugriff auf eine modifizierte Schließung (Beachten Sie, dass ich sagte 'kann' nicht 'wird' ein Problem verursachen, weil es manchmal nicht abhängig davon, was sonst in der Methode und manchmal Sie tatsächlich ist auf den modifizierten Abschluss zugreifen wollen).

Weitere Informationen:

http://blogs.msdn.com/abhinaba/archive/2005/10/18/482180.aspx

Noch mehr Infos:

http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx

http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx

http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx

+1

Es ist nicht "eine Schließung pro Methode" - es ist komplizierter als das. –

+0

Ja, mir ist klar, dass ich schlecht gelesen habe - ich habe versucht, die Situation schnell zu paraphrasieren (Raymond erklärt tiefer). Die anstößige Phrase wurde entfernt, damit die Leute die mehr Info-Links sehen können. –