Att följande kod resulterar i att tre sjuor skrivs till konsolen är ett lite märkligt faktum i C#.
List<Action> actions = new List<Action>();
for (int i = 4; i < 7; i++)
actions.Add(() => { Console.WriteLine(i.ToString()); });
foreach(Action a in actions)
a();
Att det är så beror på att C# återanvänder en och samma variabel (i
) och att de closures som samlas upp i actions
har kapslat in en referens till ett och samma i
till skillnad från det aktuella värdet av i
. Det samma gäller för övrigt foreach
-loopar.
Bästa sättet att komma runt problemet är som vanligt att inte använda de primitiva loop-konstruktionerna i C# (ForEach
-metoden på listor lider inte av det här problemet då lambdan alltid skapar ett nytt “scope”) men om man envisas skriver man lämpligen istället något i stil med:
List<Action> actions = new List<Action>();
for (int i = 4; i < 7; i++)
{
int j = i;
actions.Add(() => { Console.WriteLine(j.ToString()); });
}
foreach(Action a in actions)
a();
Erik Meijer reder ut det hela i i sin Programming Language Beauty: Look Closure. Många intressanta länkar om man inte tycker C# är så spännande längre.