Captured Closure (Loop Variable) in C# 5.0

c#, c#-5.0, closures, for-loop, foreach

Solution

What is the reasoning behind this?

I'm going to assume you mean "why wasn't it changed for `for` loops as well?"

The answer is that for `for` loops, the existing behaviour makes perfect sense. If you break a `for` loop into:

- initializer

- condition

- iterator

- body

... then the loop is roughly:

{
    initializer;
    while (condition)
    {
        body;
        iterator;
    }
}

(Except that the `iterator` is executed at the end of a `continue;` statement as well, of course.)

The initialization part logically only happens once, so it's entirely logical that there's only one "variable instantiation". Furthermore, there's no natural "initial" value of the variable on each iteration of the loop - there's nothing to say that a `for` loop has to be of a form declaring a variable in the initializer, testing it in the condition and modifying it in the iterator. What would you expect a loop like this to do:

for (int i = 0, j = 10; i < j; i++)
{
    if (someCondition)
    {
        j++;
    }
    actions.Add(() => Console.WriteLine(i, j));
}

Compare that with a `foreach` loop which looks like you're declaring a separate variable for every iteration. Heck, the variable is read-only, making it even more odd to think of it being one variable which changes between iterations. It makes perfect sense to think of a `foreach` loop as declaring a new read-only variable on each iteration with its value taken from the iterator.

Problem

This works fine (means as expected) in C# 5.0: ``` var actions = new List<Action>(); foreach (var i in Enumerable.Range(0, 10)) { actions.Add(() => Console.WriteLine(i)); } foreach (var act in actions) act(); ``` Prints 0 to 9. But this one shows 10 for 10 times: ``` var actions = new List<Action>(); for (var i = 0; i < 10; i++) { actions.Add(() => Console.WriteLine(i)); } foreach (var act in actions) act(); ``` Question: This was a problem that we had in C# versions before 5.0; so we had to use a loop-local placeholder for the closure and it's fixed now - in C# 5.0 - in "foreach" loops. But not in "for" loops! What is the reasoning behind this (not fixing the problem for `for` loops too)?

Original source

Related problems