I can't understand quite clearly the difference between two blocks of code. Consider there is a program
class Program
{
static void Main(string[] args)
{
List<Number> numbers = new List<Number>
{
new Number(1),
new Number(2),
new Number(3)
};
List<Action> actions = new List<Action>();
foreach (Number numb in numbers)
{
actions.Add(() => WriteNumber(numb));
}
Number number = null;
IEnumerator<Number> enumerator = numbers.GetEnumerator();
while (enumerator.MoveNext())
{
number = enumerator.Current;
actions.Add(() => WriteNumber(number));
}
foreach (Action action in actions)
{
action();
}
Console.ReadKey();
}
public static void WriteNumber(Number num)
{
Console.WriteLine(num.Value);
}
public class Number
{
public int Value;
public Number(int i)
{
this.Value = i;
}
}
}
The output is
1
2
3
3
3
3
These two blocks of code should work identically. But you can see that the closure is not working for the first loop. What am i missing?
Thanks in advance.
These two blocks of code should work identically.
No they shouldn't - at least in C# 5. In C# 3 and 4 they would, in fact.
But in the foreach
loop, in C# 5, you have one variable per iteration of the loop. Your lambda expression captures that variable. Subsequent iterations of the loop create different variables which don't affect the previously-captured variable.
In the while
loop, you have one variable which all the iterations capture. Changes to that variable will be seen in all of the delegates that captured it. You can see this by adding this line after your while
loop:
number = new Number(999);
Then your output would be
1
2
3
999
999
999
Now in C# 3 and 4, the foreach
specification was basically broken by design - it would capture a single variable across all iterations. This was then fixed in C# 5 to use a separate variable per iteration, which is basically what you always want with that sort of code.
See more on this question at Stackoverflow