Это классическая ошибка захвата переменной цикла.Это влияет как на циклы for
, так и foreach
: при условии типичной конструкции у вас есть единственная переменная на протяжении всего цикла.Когда переменная перехвачена лямбда-выражением или анонимным методом, это сама переменная (не значение во время захвата), которая захватывается.Если вы измените значение переменной и затем выполните делегат, делегат «увидит» это изменение.
Эрик Липперт подробно расскажет об этом в своем блоге: part 1 , part 2 .
Обычное решение - взять копию переменной внутри цикла :
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())
Причина, по которой это работаетчто каждый делегат теперь будет захватывать отдельный «экземпляр» переменной copy
.Перехваченная переменная будет той, которая создана для итерации цикла - ей присваивается значение text
для этой итерации .И вот, все это работает.