Why is iterative execution cache execution not delayed?

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 'u' from the char request collection. The main problem is that the variable c in the Where clause is not evaluated until the second foreach. My question is:

1) Why does the delegate generated by the first foreach not capture every value of c as it is created? Is there any situation that I don’t know about where this is not the desired behavior?

2) If it does not fix the value of c , how is this value still stored in the region in the second foreach, when the request is actually executed? It seems to me that if you do not store the values ​​of the transferred variables, then the attempt to resolve the operator for the second foreach will fail, because the variable c clearly beyond the scope.

I don’t understand how to “use the last value that we saw in this variable when it was in scope” was a good design decision for this circumstance, and I hoped that someone could shed some light on this topic.

+4
source share
3 answers

Capture 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: V is outside of while - this means that it was only committed once for foreach . I understand that the C # team sometimes doubted the wisdom of this change (it was inside the while in the C # 1.2 specification, which would completely fix the problem). Perhaps this will change in the end, but so far this is true for the specification.

+7
source

As Mark says, it captures the vowel as a variable, not the vowel value in each case. This is almost always undesirable, but it is a given behavior (i.e., the Compiler complies with the language specification). There is one vowel variable, not a “new instance of the variable” for each iteration.

Please note that the expression tree is not involved here - you are using IEnumerable<T> , so just convert the lambda expression to a delegate.

See section 7.14.4 of the C # 3 specification for more information.

+4
source

I think you really want to do something more here:

 IEnumerable<char> query = "Not what you might expect"; query = query.Except("aeiou"); foreach (char Output in query) { System.Out.WriteLine(Output); } 
+1
source

Source: https://habr.com/ru/post/1285961/


All Articles