I met an interesting issue about C#. I have code like below.
List<Func<int>> actions = new List<Func<int>>(); int variable = 0; while (variable < 5) { actions.Add(() => variable * 2); ++ variable; } foreach (var act in actions) { Console.WriteLine(act.Invoke()); }
I expect it to output 0, 2, 4, 6, 8. However, it actually outputs five 10s.
It seems that it is due to all actions referring to one captured variable. As a result, when they get invoked, they all have same output.
Is there a way to work round this limit to have each action instance have its own captured variable?
Yes – take a copy of the variable inside the loop:
You can think of it as if the C# compiler creates a ‘new’ local variable every time it hits the variable declaration. In fact it’ll create appropriate new closure objects, and it gets complicated (in terms of implementation) if you refer to variables in multiple scopes, but it works 🙂
Note that a more common occurrence of this problem is using
fororforeach:See section 7.14.4.2 of the C# 3.0 spec for more details of this, and my article on closures has more examples too.
Note that as of the C# 5 compiler and beyond (even when specifying an earlier version of C#), the behavior of
foreachchanged so you no longer need to make local copy. See this answer for more details.