Consider the following example:
IEnumerable<Int32> groupsToAdd = new List<Int32>();
List<Int32> groups1 = new List<Int32>() { 1,2,3 };
List<Int32> groups2 = new List<Int32>() { 3,4,5 };
groupsToAdd = groups1.Where(g => false == groups2.Contains(g));
groups2.AddRange(groupsToAdd);
groupsToAdd.Dump();
When groupsToAdd.Dump()
is called the list is now empty. I've looked up the AddRange reference and it doesn't mention that the elements are removed from list but when i test this code (in linqpad) it ends empty. Why is this?
Edit:
To clarify, I mean that the elements are being removed from groupsToAdd
because before groups2.AddRange(groupsToAdd)
groupsToAdd is populated with two elements
What's important to remember, when using LINQ, is that it results in a query, not the results of that query. groupsToAdd
is not a list of items, it's just the definition of a query that is able to get some items when it needs to.
groupsToAdd
doesn't actually iterate the source sequence (which is groups1
) or perform the predicate checks (which is dependant on the state of groups2
) until it is iterated.
You iterate groupsToAdd
twice. Once with the call to AddRange
, and again with the call to Dump
. The second time you're iterating it group2
has changed, and thus the results of the query have changed as well.
If you want to avoid this deferred execution then you can materialize the query right away by modifying your code to be something like:
groupsToAdd = groups1.Where(g => false == groups2.Contains(g));
.ToList();
This will evaluate the query at that moment in time so that groupsToAdd
will represent the results of the query instead of the query itself.