The key point here is that closures are closed over variables, not over values. Thus, the value of this variable at the moment you close it does not matter. The value of this variable is important when invoking an anonymous method.
How this happens is easy enough to see when you see that the compiler converts the closure. This will create something morally similar to this:
public class ClosureClass1 { public int i; public void AnonyousMethod1() { Console.WriteLine(i); } } static void Main(string[] args) { ClosureClass1 closure1 = new ClosureClass1(); for (closure1.i = 0; closure1.i < 10; closure1.i++) new Thread(closure1.AnonyousMethod1).Start(); }
So here we can see more clearly what is happening. There is one copy of the variable, and now this variable has been translated into the field of the new class instead of the local one. Anywhere that would change a local variable now changes the field of this instance. Now we can understand why your code prints what it does. After starting a new thread, but before its actual execution, the for loop in the main thread returns and increases the value of the variable in closing. A variable that has not yet been read by the closure.
To get the desired result, you need to make sure that instead of closing each iteration of the loop over one variable, they need each of them to have a variable that they close:
for (int i = 0; i < 10; i++) { int copy = i; new Thread(() => Console.WriteLine(copy)); }
Now the copy variable never changes after it is closed, and our program will print 0-9 (although in random order, since threads can be scheduled, but the OS wants it).
Servy
source share