Почему эти результаты linq отличаются?
1-й оператор:
IEnumerable<char> query = "Not what you might expect";
query = query.Where (c => c != 'a');
query = query.Where (c => c != 'e');
query = query.Where (c => c != 'i');
query = query.Where (c => c != 'o');
query = query.Where (c => c != 'u');
Вывод String.Join("", query)
: "Nt wht y mght xpct"
2-й оператор:
query = "Not what you might expect";
foreach (char vowel in "aeiou")
query = query.Where (c => c != vowel);
Выход String.Join("", query)
: "Not what yo might expect"
Выходы из этих операторов различны.
Может ли кто-нибудь объяснить, почему?
Ответы
Ответ 1
Если вы используете версию С# ниже 5.0 (где это исправлено), вот почему:
Лямбда в вашем запросе захватывает переменную цикла vowel
.
Поскольку Linq любит использовать отложенное выполнение, значение этой ссылки не считывается до тех пор, пока запрос не будет выполнен (итерацией по нему), который после завершения цикла foreach
завершен. В этот момент самое последнее значение vowel
равно u
, поэтому вы получаете неожиданный вывод.
Вы можете обойти это, скопировав значение в другую временную переменную (или обновив до С# 5.0).
Попробуйте следующее:
query = "Probably what you might expect";
foreach (char vowel in "aeiou") {
char currentVowel = vowel;
query = query.Where (c => c != currentVowel );
}
Ответ 2
Это потому, что вы создаете закрытие по переменной vowel
, которая изменяется во времени. Сохраните его значение в отдельной переменной, и он будет работать:
query = "Not what you might expect";
foreach (char vowel in "aeiou")
{
var current = vowel;
query = query.Where (c => c != current);
}
Ответ 3
Читайте о закрытии. Если вы используете .NET 4.0
и ниже, вы получите другой результат. В .NET 4.5
это поведение изменяется (фиксировано). См. Также, как компилятор расширяет foreach
.