Awais Mahmood Awais Mahmood - 13 days ago 7
C# Question

How ToList() is working here?

This might be rather trivial but I am unable to understand this from sometime. I need to remove some items from a collection. I have a list of my model which is filled from database. I further extracted different collections from that list and then tried to remove some items but it didn't work in the way I thought it to be

List<MyModel> temp = DbHelper.Select("Tree"); // count of temp is 40
var _doc = temp.Where(x => x.Parent == code + "02"); // count of _doc is 9
// type of _doc is System.Linq.Enumerable.WhereListIterator<MyModel>
var cd = _doc.ToList().RemoveAll(x => x.S7 == "CDFL"); // cd is 2


Since cd has value 2 so, 2 items should be removed from _doc. But _doc has still 9 items in it.

But then I changed the type of _doc to list as follows:

var _doc = temp.Where(x => x.Parent == code + "02").ToList(); // count of _doc is 9
// type of _doc is List<MyModel>
var cd = _doc.RemoveAll(x => x.S7 == "CDFL"); // cd is 2


And the count of _doc is 7 which is correct.

The RemoveAll is being called on a type of List in both cases so, why the behavior is different in both?

Answer

This following line of code

var _doc = temp.Where(x => x.Parent == code + "02").ToList(); 

creates a new list from the items of temp that passed the filtered.

Then at the following line

var cd = _doc.RemoveAll(x => x.S7 == "CDFL"); 

You remove those items from this list, the resulted form the ToList.

Whereas in the following line

var _doc = temp.Where(x => x.Parent == code + "02");

you just define a linq query and you don't force to be executed. The type of _doc now is a IEnumerable<T> where T is the type of x. In order to see which items pass this filter you have to force it to be executed. This can be done with many ways. Some of them are the following

  • By looping through this sequence using a foreach statement.
  • By calling ToList
  • By calling ToArray

Now the critical point is in the following line:

var cd = _doc.ToList().RemoveAll(x => x.S7 == "CDFL"); 

Let's take it piece by piece. As I mentioned above _doc.ToList() would create a new Lit<T>. Then you apply the RemoveAll on this list.

That's the difference. The _doc would have the same reference as it had before you called the ToList. Furthermore, the RemoveAll would have been applied to the list that has been created from the call of ToList.

Query Execution at this link you would find more info and you would read about two very common terms in situations like this, deferred query execution and immediate query exeqution.