2

Say I have this block of code in C#:

static void Main(string[] args)
{
    List<Func<int>> fs = new List<Func<int>>();

    for (int i = 0; i < 5; i++)
        fs.Add(() => { return i; });

    for (int i = 0; i < 5; i++)
        Console.WriteLine(fs[i]());

    Console.ReadLine();
}

When I run it, I expected it to print

0
1
2
3
4

but it prints

5
5
5
5
5

instead. My understanding is that the code in Func only keeps an address to i instead of getting the value of i, and this approach should be avoided.

So my question is that, is there a way to capture the local variables and pass them into Func by value?

Dbl
  • 5,634
  • 3
  • 41
  • 66
Tengyu Liu
  • 1,223
  • 2
  • 15
  • 36
  • 1
    I have not found it yet, but I know there are duplicates of this. See also [Closing over the loop variable considered harmful](http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx) – crashmstr Jul 31 '14 at 14:13

2 Answers2

4

You can use the scope in the for loop to capture a copy of the value of i:

static void Main(string[] args)
{
    List<Func<int>> fs = new List<Func<int>>();

    for (int i = 0; i < 5; i++)
    {
        var copyOfi = i;
        fs.Add(() => { return copyOfi; });
    }

    for (int i = 0; i < 5; i++)
        Console.WriteLine(fs[i]());

    Console.ReadLine();
}
Rui
  • 4,847
  • 3
  • 29
  • 35
1

Just store the loop variable in a local variable inside the loop and use it in the lambda expression.

Thierry
  • 342
  • 2
  • 6