int age = 30;
Action printAge = () => Console.WriteLine(age);
age++;
printAge();
prints 31, not 30.
Up until C# 4.0 there was one context in which closures didn't act as most people would expect. Consider the following:
var actions = new Action[3];
int i = 0;
foreach (var c in "dog") {
actions[i++] = () => Console.Write(c);
}
foreach (var action in actions) {
action();
}
Prior to C# 5.0 this printed "ggg". In effect the variable c persisted over each iteration of the first foreach, making it equivalent to:
char c;
for (int i = 0; i < 3; i++) {
c = "dog"[i];
actions[i] = () => Console.Write(c);
}
On the third time through the loop c is set to "g". Therefore, when the closures are executed c is evaluated to be "g", and so that's what's printed out three times.
If you wrote the loop using for as shown above then this is what you should expect. However, if you used the original foreach you would probably expect the output to be "dog", and starting with C# 5.0 that's what it is. In effect, from C# 5.0 on, the foreach loop is equivalent to:
for (int i = 0; i < 3; i++) {
char c = "dog"[i];
actions[i] = () => Console.Write(c);
}
Note this is a breaking change as code compiled prior to and since C# 5.0 will behave differently. However, it was felt that the change was worth it as it cleared up confusing behaviour.
No comments:
Post a Comment