I found an interesting behavior of the LINQ queries result while working with C#. I try to figure this out, but couldn't find a proper explanation of why this works as it is. So I'm asking here, maybe someone can give a good explanation (of the inner working that leads to this behaviour) to me or maybe some links.
I have this class:
public class A
{
public int Id { get; set; }
public int? ParentId { get; set; }
}
And this object:
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 }
};
And my code, that works with this object:
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
So, Count of result
variable is 1, valuesToInsert
count is 2, and after the foreach loop (which doesn't change the valuesToInsert
explicitly) count of the valuesToInsert
is changing. And, although at the start of the foreach
count of valuesToInsert
was two, foreach
makes three iterations.
So why value of this Enumerable can be changed inside foreach
? And, for example, if I use this code to change the value of Enumerable:
var testEn = list.Where(x => x.Id == 1);
foreach (var x in testEn)
{
list.Add(new A { Id = 1 });
}
I get the System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
. What's the differences between them? Why one collection can be modified and other can not?
P.S. If I add ToList()
like this:
var valuesToInsert = list.Where(x => result.Any(y => y.Id == x.ParentId)).ToList();
Or like this:
foreach (var value in valuesToInsert.ToList())
It makes only two iterations.