You asked for a reference to the specification; the relevant location is section 8.8.4, which states that a "foreach" loop is equivalent to:
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
Note that the value v is declared outside the while loop, and therefore there is a single loop variable. That is then closed over by the lambda.
UPDATE
Because so many people run into this problem the C# design and compiler team changed C# 5 to have these semantics:
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded-statement
}
Which then has the expected behaviour -- you close over a different variable every time. Technically that is a breaking change, but the number of people who depend on the weird behaviour you are experiencing is hopefully very small.
Be aware that C# 2, 3, and 4 are now incompatible with C# 5 in this regard. Also note that the change only applies to foreach
, not to for
loops.
See http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ for details.
Commenter abergmeier states:
C# is the only language that has this strange behavior.
This statement is categorically false. Consider the following JavaScript:
var funcs = [];
var results = [];
for(prop in { a : 10, b : 20 })
{
funcs.push(function() { return prop; });
results.push(funcs[0]());
}
abergmeier, would you care to take a guess as to what are the contents of results
?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…