Why is this considered something that should be considered worth warning people about?
I ask, purely in the spirit of furthering my own eduction.
--
Stuart
1 Answer, 1 is accepted
0
Zdravko
Telerik team
answered on 13 Nov 2012, 10:00 AM
Hello,
Thanks for contacting us.
For an example I will give you the following code:
var values = new List<int>() { 100, 110, 120 };
var funcs = new List<Func<int>>();
foreach(var v in values)
funcs.Add( ()=>v );
foreach(var f in funcs)
Console.WriteLine(f());
In versions older than C# 5 this code will return values 120/ 120/ 120.
Because ()=>v means "return the current value of variable v", not "return the value v was back when the delegate was created". Closures close over variables, not over values. And when the methods run, clearly the last value that was assigned to v was 120, so it still has that value.
This is how the loop body is implemented in the versions before C# 5:
{
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
try
{
int m; // OUTSIDE THE ACTUAL LOOP
while(e.MoveNext())
{
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
}
and in version C# 5 the variable is moved inside the loop body so a fresh variable is created:
try
{
while(e.MoveNext())
{
int m; // INSIDE
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
Each closure is closed over a different variable, which is only assigned to once, so it always keeps the correct value.