Dies ist eine Erweiterung der Frage von Access to Modified Closure . Ich möchte nur überprüfen, ob das Folgende tatsächlich sicher genug für die Verwendung in der Produktion ist.
List<string> lists = new List<string>();
//Code to retrieve lists from DB
foreach (string list in lists)
{
Button btn = new Button();
btn.Click += new EventHandler(delegate { MessageBox.Show(list); });
}
Ich laufe die oben genannten nur einmal pro Start durch. Im Moment scheint es in Ordnung zu funktionieren. Wie Jon über kontraintuitives Ergebnis in einigen Fällen erwähnt hat. Was muss ich hier beachten? Wird es in Ordnung sein, wenn die Liste mehr als einmal durchlaufen wird?
Antworten:
Vor C # 5 müssen Sie eine Variable in foreach erneut deklarieren. Andernfalls wird sie gemeinsam genutzt, und alle Ihre Handler verwenden die letzte Zeichenfolge:
Beachten Sie, dass sich dies ab C # 5 geändert hat und Sie dies insbesondere im Fall von
foreach
nicht mehr tun müssen: Der Code in der Frage würde wie erwartet funktionieren.Beachten Sie Folgendes, um zu zeigen, dass dies ohne diese Änderung nicht funktioniert:
Führen Sie die obigen Schritte vor C # 5 aus . Obwohl jede Schaltfläche einen anderen Namen aufweist, wird beim Klicken auf die Schaltflächen viermal "Wilma" angezeigt.
Dies liegt daran, dass die Sprachspezifikation (ECMA 334 v4, 15.8.4) (vor C # 5) definiert:
Beachten Sie, dass die Variable
v
(die Ihre istlist
) außerhalb der Schleife deklariert ist . Nach den Regeln der erfassten Variablen teilen sich alle Iterationen der Liste den Inhaber der erfassten Variablen.Ab C # 5 wird dies geändert: Die Iterationsvariable (
v
) befindet sich innerhalb der Schleife. Ich habe keine Spezifikationsreferenz, aber es wird im Grunde:Abmelden; Wenn Sie einen anonymen Handler aktiv abbestellen möchten, besteht der Trick darin, den Handler selbst zu erfassen:
Ebenso, wenn Sie einen einmaligen Ereignishandler (wie z. B. Laden usw.) möchten:
Dies ist jetzt selbst abbestellend ;-p
quelle
for
ist unverändert in 5.0