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.