Questo è un classico errore di catturare una variabile del ciclo. Ciò riguarda sia i cicli for
e foreach
: presupponendo una costruzione tipica, si dispone di una singola variabile per l'intera durata del ciclo. Quando una variabile viene catturata da un'espressione lambda o da un metodo anonimo, è la variabile stessa (non il valore al momento dell'acquisizione) che viene catturata. Se si modifica il valore della variabile e quindi si esegue il delegato, il delegato "vedrà" quella modifica.
Eric Lippert è molto dettagliato nel suo blog: part 1, part 2.
La soluzione più comune è quello di prendere una copia della variabile all'interno del ciclo:
string[] source = new string[] {"this", "that", "other"};
List<Thread> testThreads = new List<Thread>();
foreach (string text in source)
{
string copy = text;
testThreads.Add(new Thread(() =>
{
Console.WriteLine(copy);
}));
}
testThreads.ForEach(t => t.Start())
Il motivo per cui funziona è che ogni delegato ora catturare una "istanza" diverso della variabile copy
.La variabile acquisita sarà quella creata per l'iterazione del ciclo, a cui viene assegnato il valore di text
per tale iterazione. Ecco, tutto funziona.
fonte
2010-07-01 18:35:03
eccoci di nuovo .... – leppie
Questo dovrebbe essere un avvertimento del compilatore come in VB. Penso che sia stupido per il team C# non avvertire le persone dei potenziali problemi. –
Duplicato di: [C# - L'identificativo e le chiusure foreach] (http://stackoverflow.com/questions/512166/c-the-foreach-identifier-and-closures) – Shog9