This is a classic mistake of capturing a loop variable. This affects both for
and foreach
loops: assuming a typical construction, you have a single variable across the whole duration of the loop. When a variable is captured by a lambda expression or an anonymous method, it's the variable itself (not the value at the time of capture) which is captured. If you change the value of the variable and then execute the delegate, the delegate will "see" that change.
Eric Lippert goes into great detail on it in his blog: part 1, part 2.
The usual solution is to take a copy of the variable inside the loop:
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())
The reason this works is that each delegate will now capture a different "instance" of the copy
variable. The variable captured will be the one created for the iteration of the loop - which is assigned the value of text
for that iteration. Lo and behold, it all works.