Why am I getting the wrong results when calling Func <int>?

I have the following code snippet in C #:

var actions = new List<Func<int>>(); IEnumerable<int> values = new List<int> { 1, 2, 3 }; foreach (int value in values) { actions.Add(() => value * value); } foreach (var action in actions) { Console.WriteLine(action()); ; } Console.ReadLine(); 

It works fine, but I do not get the expected result.

Actual result

9,9,9

Expected Result

1,4,9

Why am I not getting the expected result?

+6
c # lambda
source share
2 answers

You commit the loop variable in your lambda expression, which means that when the delegate is finally called, it sees the final value of the loop variable.

Simple fix:

 foreach (int value in values) { int copy = value; actions.Add(() => copy * copy); } 

Thus, you get a new copy variable at each iteration of the loop, so each delegate expression will capture another variable, and the loop variable ( value ) does not change over time.

Eric Lippert explains this well in β€œClosing on a variable cycle is considered harmful” (and part two ).

This is basically a "gotcha" in C #, which almost everyone crashes sooner or later.

+12
source share

You need to commit the variable inside the loop. Right now, your pending execution actions use the last value from the first foreach .

 var actions = new List<Func<int>>(); IEnumerable<int> values = new List<int> { 1, 2, 3 }; foreach (int value in values) { var v = value; actions.Add(() => v * v); } foreach (var action in actions) { Console.WriteLine(action()); ; } Console.ReadLine(); 

Pay attention to the line var v = value; .

+13
source share

All Articles