Почему этот запрос LINQ не выполняется при использовании foreach?
При создании новых объектов в операторе LINQ, например:
var list = new List<string>() { "a", "b", "c" };
var created = from i in list select new A();
С классом A выглядит так:
class A
{
public string Label;
}
И затем изменение свойств в с циклом foreach:
foreach (var c in created) {
c.Label = "Set";
}
Почему значения не задаются при обращении к объектам в IEnumerable
. Например. следующее утверждение не выполняется:
Assert.AreEqual("Set", created.ElementAt(2).Label);
Интересно, почему это происходит. Я бы ожидал, что оператор foreach выполнит запрос и инициирует создание объектов. Документация MSDN гласит: "Выполнение запроса отложено до тех пор, пока переменная запроса не будет повторена в foreach или For Each loop" .
Я воспроизвел это поведение с .NET 4.5 и Mono 3.2.0. Вызов ToList
в IEnumerable
перед доступом к созданному объекту делает эту проблему упущенной.
Ответы
Ответ 1
Это происходит потому, что created
- это запрос, а не результат. Итак, каждый раз, когда вы перечисляете его, вы снова оцениваете Select
с нуля.
Если вы хотите, чтобы это сработало, сделайте created
фактический список, а не только IEnumerable
, представляющий запрос.
Например, добавьте:
created = created.ToList();
Вы говорите:
Я бы ожидал, что оператор foreach выполнит запрос и вызовет создание объектов
Это именно то, что происходит. Проблема в том, что создание объектов происходит каждый раз, когда вы перебираете created
, а не только в первый раз. Поскольку метод ElementAt()
выполняет итерацию по created
, он снова создает новый A
.