Я обнаружил интересное поведение результатов запросов LINQ при работе с C#. Я пытаюсь понять это, но не могу найти правильного объяснения, почему это работает так, как есть. Поэтому я спрашиваю здесь, может быть, кто-то может дать мне хорошее объяснение (внутренней работы, которая приводит к такому поведению) или, возможно, некоторые ссылки.
У меня есть этот класс:
public class A
{
public int Id { get; set; }
public int? ParentId { get; set; }
}
И этот объект:
var list = new List<A>
{
new A { Id = 1, ParentId = null },
new A { Id = 2, ParentId = 1 },
new A { Id = 3, ParentId = 1 },
new A { Id = 4, ParentId = 3 },
new A { Id = 5, ParentId = 7 }
};
И мой код, который работает с этим объектом:
var result = list.Where(x => x.Id == 1).ToList();
var valuesToInsert = list.Where(x => result.Any(y => y.Id == x.ParentId));
Console.WriteLine(result.Count); // 1
Console.WriteLine(valuesToInsert.Count()); //2
foreach (var value in valuesToInsert)
{
result.Add(value);
}
Console.WriteLine(valuesToInsert.Count()); //3. collection (and its count) was changed inside the foreach loop
Console.WriteLine(result.Count); //4
Итак, переменная Count result
равна 1, valuesToInsert
count равна 2, и после foreach l oop (который явно не меняет valuesToInsert
) счетчик valuesToInsert
меняется. И, хотя в начале foreach
число valuesToInsert
было две , foreach
делает три итерации.
Так почему значение этого перечислимого можно изменить внутри foreach
? И, например, если я использую этот код для изменения значения Enumerable:
var testEn = list.Where(x => x.Id == 1);
foreach (var x in testEn)
{
list.Add(new A { Id = 1 });
}
, я получу System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
. Какая разница между ними? Почему одна коллекция может быть изменена, а другая - нет?
PS Если я добавлю ToList()
вот так:
var valuesToInsert = list.Where(x => result.Any(y => y.Id == x.ParentId)).ToList();
Или вот так:
foreach (var value in valuesToInsert.ToList())
Это делает только две итерации.