tags:

views:

145

answers:

6

This function returns 1210 but not 385, why ?

public int CalcSquaresSum() {
    int sumOfSquares = 0;
    List<Func<int>> functions = new List<Func<int>>();
    for (int i = 1; i <= 10; i++) {
        functions.Add(() => i * i);
    }

    foreach (var function in functions) {
        sumOfSquares += function(); // why function() is always 121
    }

    return sumOfSquares;
}
+7  A: 

In your code the loop variable i is common to all functions and it will be left to it's last value, 11, which will be later used to calculate the sum.

If you change the loop to assign the variable to the functions in a scope that is not shared, like this...

  for(int i = 1;i <= 10;i++) {
    int n = i;
    functions.Add(() => n * n);
  }

...the function will return 385.

Skrim
+5  A: 

Because the value of i is 11 at the end of your loop. You've added a bunch of functions to the list - not values - but the functions all point to a single int, which obviously can only have one value. It was declared once, at the beginning of your for statement. As with any variable, its value will be the last thing you did to it. When those functions actually run, they all run against that one value.

If you declare a new variable inside the loop, that one will never change (never be reassigned) so when the function runs, it will still have a reference to an untouched value.

Rex M
+2  A: 

You are referencing a mutating variable, and not capturing the value.

The other answers shows you how to do this.

leppie
A: 

i*i gets evaluated only just after you call function()..
At that moment i==11

Funny though because I'd expect i not to be available anymore.. :D

Julian de Wit
A: 

By adding a list of delegates in the first loop, you've created what is known as a closure. Effectively, your local variable with scope apparently limited to the loop is now stored as a member of a nested class (generated by the compiler). This is why, when you execute the second loop, the closure-version of the loop variable is used. Since it's only used once the first loop has completed, all "values of i" are now 11.

So, the result will be: 10 * (11*11) = 1210.

Eric Smith
A: 

For the sake of curiosity, here is what the compiler actually generates when you write that code:

[System.Runtime.CompilerServices.CompilerGenerated]
private sealed class AnomClass
{
    public int i;

    public int CalcSquaresSum_AnonFunc() {
     return (this.i * this.i);
    }
}

public int CalcSquaresSum()
{
    int sumOfSquares = 0;
    List<Func<int>> functions = new List<Func<int>>();

    AnomClass anonObj = new AnomClass();
    Func<int> anonFunc = null;

    for (anonObj.i = 1; anonObj.i <= 10; anonObj.i++) {
     if (anonFunc == null)
      anonFunc = new Func<int>(anonObj.CalcSquaresSum_AnonFunc);
     functions.Add(anonFunc);
    }

    foreach (Func<int> function in functions) {
     sumOfSquares += function();
    }
    return sumOfSquares;
}

As you can see, there's no magic involved. The anonymous method can only access a variable that is declared outside of its scope because it's not really declared outside of its scope.

What really happens is that the variable i s moved to an invisible class. The anonymous method resides on that class. From there it can access i directly. Inside the CalcSquaresSum method, the references to i are all translated as a reference to the invisible class.

Notice that the variable sumOfSquares receive the same treatment. Of course, that happens because the compiler is smart enough to realize that only i was used by the anonymous method.

jpbochi