1

I have this code and do not understand why the out put is 22! I am afraid it should be 01! can anyone explain what happens? if the list store a method with a parameter, so the parameters should be 0 and 1 respectively!

List<Action> list = new List<Action>();

for (int i = 0; i < 2; i++)
{
    list.Add(() => Console.Write(i));
}

foreach (var it in list)
{
    it();
} 
Talenel
  • 422
  • 2
  • 6
  • 25

3 Answers3

3

It is Closure (1, 2).

In your case Console.Write(i) will use value of i in the moment of action call. You firstly increment i in for loop then in second loop you call every action in the list. In the moment of call of every action i has value 2 - so, you get 22 as output.

To get expected result you should create local copy of i and use it:

for (int i = 0; i < 2; i++)
{
    var temp = i; 
    list.Add(() => Console.Write(temp));
}
Roman
  • 11,966
  • 10
  • 38
  • 47
2

Addition to Roma Doskoch's anwser, another approach is to avoid for.

var list = Enumerable
               .Range(0, 2)
               .Select<int, Action>(i => () => Console.Write(i));
qxg
  • 6,955
  • 1
  • 28
  • 36
1

Closures capture variables, not values.

In your code, the closure captures the variable i, not whatever value happens to be stored in i on each iteration. When you invoke the action, the variable i has a value of 2 (because the loop has finished) and therefore 2 will be printed out twice.

In order to avoid this, as other answers already point out, you need to create a new variable every time around as a workaround to not being able to capture values; if you declare a new variable on every iteration then the result of capturing the variable is equivalent to capturing the value because you won't be changing it on the next iteration.

InBetween
  • 32,319
  • 3
  • 50
  • 90