How do closures close between foreach and list.ForEach ()?

Consider this code.

        var values = new List<int> {123, 432, 768};

        var funcs = new List<Func<int>>();

        values.ForEach(v=>funcs.Add(()=>v));

        funcs.ForEach(f=>Console.WriteLine(f()));//prints 123,432,768

        funcs.Clear();

        foreach (var v1 in values)
        {
            funcs.Add(()=>v1);
        }

        foreach (var func in funcs)
        {
            Console.WriteLine(func());  //prints 768,768,768
        } 

I know that the second foreach prints 768 3 times due to the closing variable captured by the lambda. why doesn't this happen in the first case? How is a keyword foreachdifferent from a method foreach? Is this a beacose expression evaluated when I dovalues.ForEach

+5
source share
2 answers

foreachintroduces only one variable. While the parameter variable lambda is "fresh" with every call.

Compare with:

foreach (var v1 in values) // v1 *same* variable each loop, value changed
{
   var freshV1 = v1; // freshV1 is *new* variable each loop
   funcs.Add(() => freshV1);
} 

foreach (var func in funcs)
{
   Console.WriteLine(func()); //prints 123,432,768
}

I.e

foreach (T v in ...) { }

can be described as:

T v;
foreach(v in ...) {}

Happy coding.

+9
source

, foreach v1, . values - ... , .

List<T>.ForEach ( f) - - , .

- , #.

+6

All Articles