Take the code below, adapted from this question:
//Borrowed from another question because its a simpler example of what happened to me.
IEnumerable<char> query = "Not what you might expect";
foreach(char vowel in "aeiou")
{
query = query.Where(c => c != vowel);
}
foreach (char Output in query)
{
System.Out.WriteLine(Output);
}
This only removes the 'u' from the query char collection. The core issue has something to do with the fact that the c
variable in the Where
clause isn't evaluated until the second foreach. My question is:
1) Why would the delegate generated by the first foreach not capture each value of c
as it is built up? Is there some situation I'm unaware of where that is not the desired behavior?
2) If its not capturing the value of c
, how is that value even still in scope in the second foreach when the query is actually run? It would seem to me that if its not storing the values of the variables being passed in, then trying to resolve the statement for the second foreach would fail because the the variable c
is clearly out of scope.
I don't understand how it is that 'use the last value we saw on this variable back when it was in scope' was a good design decision for this circumstance, and was hoping someone could shed some light on the subject.
It is capturing vowel
; try:
foreach(char vowel in "aeiou") {
char tmp = vowel;
query = query.Where(c => c != tmp);
}
Jon has a list of related posts here.
As for why... foreach
is defined (in ECMA 334v4 §15.8.4) as:
A foreach statement of the form `foreach (V v in x) embedded-statement` is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
Note the V
is outside the while
- this means it is captured once only for the foreach
. I gather that the C# team have, at times, doubted the wisdom of this change (it was inside the while
in the C# 1.2 spec, which would have avoided the problem completely). Maybe it'll change back eventually, but for now it is being true to the specification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With