This is a question based on the article "Closing over the loop variable considered harmful" by Eric Lippert.
It is a good read, Eric explains why after this piece of code all funcs will return the last value in v:
var funcs = new List<Func<int>>();
foreach (var v in values)
{
funcs.Add(() => v);
}
And the correct version looks like:
foreach (var v in values)
{
int v2 = v;
funcs.Add(() => v2);
}
Now my question is how and where are those captured 'v2' variables stored. In my understanding of the stack, all those v2 variables would occupy the same piece of memory.
My first thought was boxing, each func member keeping a reference to a boxed v2. But that would not explain the first case.
Ordinarily the variable v2
would be allocated some space on the stack at the start of the code block its found in. At the end of the code block (i.e. the end of the iteration) the stack is wound back (I'm describing the logical scenario not an optimised actual behaviour). Hence each v2
is in effect a different v2
from the previous iteration although its true that it would end up occupying the same memory location.
However the compiler spots that v2
is being used by an anonymous function created by the lambda. What the compiler does is hoist the v2
variable. The compiler creates a new class that has an Int32 field to hold the value of v2
, it is not allocated a place on the stack. It also makes the anonymous function a method of this new type. (For simplicity I'll give this un-named class a name, lets call it "Thing").
Now in each iteration a new instance of "Thing" is created and when v2
is assigned its the Int32 field which is actually assigned not just a point in stack memory. The anonymous function expression (the lambda) will now return a delegate which has non-null instance object reference, this reference will be to the current instance of "Thing".
When the delegate for anonymous function is invoked it will execute as an instance method of a "Thing" instance. Hence v2
is available as a member field and will have the value give it during the iteration this instance of "Thing" was created.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With