3 ms·
An interesting change in C# 5.0 involves the handling of foreach iteration variables when used in closure scope. This is technically a breaking change, althoug
by skwirl 13y ago
An interesting change in C# 5.0 involves the handling of foreach iteration variables when used in closure scope. This is technically a breaking change, although it is really hard to think of a case where the old behavior was legitimately desired.
Consider (stolen from the spec doc):
int[] values = { 7, 9, 13 };
Action f = null;
foreach (var value in values)
{
if (f == null) f = () => Console.WriteLine("First value: " + value);
}
f();
In previous versions of C#, there is a single value variable is in the scope of the entire loop, so the above code would actually print out the last value in the list because that was the value of value (sorry) when the loop finished. In C# 5.0, a value variable is actually in the scope of each individual iteration (so within the braces). So now if you use your iteration variable in a closure scope it won't change on you when the loop iterates and the above code actually prints out the first value.
The same cannot be said for a for loop. It still functions as it always has.
- danbruc 13y agoHere is Eric Lippert discussing the pros and cons of making the change. http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closi...
- gnaritas 13y agoShould have been that way from the beginning; having the loop variable have function scope was absurd to begin with and forced developers to copy the loop var to a local before using it in a lambda.
- skwirl 13y agoYeah, they could have made the change in C# 3.0. I just don't think anyone really felt the pain until the Task Parallel Library came along in .NET 4. Since the TPL API is lambda heavy people really started using lambdas for asynchronous tasks, which leads (or used to lead, anyway) to pain and misery when using a loop iteration variable. It could always be worse, though. Look at JavaScript. Simply copying the loop variable in the body of the loop doesn't work because all variables are scoped at the function level. So your "local" loop variable is actually a single instance for the entire function and you have the same exact problem. Instead, you have to actually create another function and immediately execute it with the loop iteration variable as an argument, and then use the parameter within the function to do whatever you wanted to do. Not cool.
- gnaritas 13y agoAgreed.
- keyle 13y agoGood nitpicking. But as you indicated, the change of behaviour should only affect people with a very dubious/interesting approach.
- seanmcdirmid 13y agoNo, this bug was encountered often by myself and many of my colleagues. Because I was so familiar with the problem, I could guess that this was a problem in their code after looking at it for a few seconds. It really was a horrible wart that needed to be fixed. Now if they would only fix the misleading lying dishonest "downcast on type bound" compiler error messages, then C# would lack warts all together.
- sk5t 13y agoSame here, it bit me quite a few times and was highly irritating each time. Very annoying to choose between copying the loop variable, or passing it off to some other method to gin up an action/func safely.
- pixie_ 13y agoThe OP wasn't saying, 'this bug isn't a big deal.' He's saying, 'the bug fix shouldn't break existing programs.' Because people, like you, designed around this. Few people, if any, designed their apps to rely on the value in the loop not changing - that's why this 'breaking fix' should break almost no programs.
- seanmcdirmid 13y agoYes, you are right, my reading comprehension of OP's comment sucks.