Consider this code:
public delegate void AnAction(); private static ListgetActions() { List actions = new List (); for (int i = 0; i < 10; i++) { actions.Add(delegate() { Console.WriteLine("i is:" + i); }); } return actions; } static void Main(String[] args) { List actions= getActions(); foreach (AnAction action in actions) { action(); } }
If you run this code, you do not get a series of lines stating “i is: 0″ through “i is: 9″. You do not get any errors, warnings, or exceptions at either compile or run time either.
What you get is this:
i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10 i is: 10
When the delegate is added to the collection of delegates, it’s using the actual variable “i”, not the object that the variable is referencing at the time. (This applies for both reference and value types.) By the time the delegate collection is accessed and the actions are invoked, “i” has the value “10″ (which, by the way, is outside the normal operating range of the loop), even though “i” is no longer in “normal” scope.
This almost makes some sense, even though I think it’s counter-intuitive (and thus bug-encouraging). The .NET inventors had to choose between referencing the variable and referencing the value; there’s use cases for both. However, it starts getting really strange when you make a copy of the variable, as in this replacement code:
private static ListgetActions() { List actions = new List (); for (int i = 0; i < 10; i++) { int x = i; actions.Add(delegate() { Console.WriteLine("i is:" + i + ", x is:" + x); }); } return actions; }
i is:10, x is:0 i is:10, x is:1 i is:10, x is:2 i is:10, x is:3 i is:10, x is:4 i is:10, x is:5 i is:10, x is:6 i is:10, x is:7 i is:10, x is:8 i is:10, x is:9
Upon invocation, the delegate references the variable "i" but the value of "x". How and why it makes that choice is beyond me.