Should I call ToList() inside foreach C#

Viewed 790

Is this code normal?

Should I call ToList(). If yes why?

It is an entity framework. Or It doesn't matter and I may not call to list?

var followers = from user in project.Followers
                where followersIds.Contains(user.Id)
                select user;

foreach (var follower in followers.ToList())
{
     project.Followers.Remove(follower);
}
2 Answers

The ToList is there to avoid running into a collection modified while iterating runtime error. ToList() makes an eager copy of the collection and then you iterate over it removing items form the original source project.Followers.

It looks kind of hacky but that is the reason why ToList is there.

Well, assuming you are using Entity Framework (from tags).
When you execute the Linq expression you get an IQueryable collection. This IQueryable is not a truthy collection stored in memory with all the records fetched from the DB, it's kinda a statement where to query to the database server. I mean, You will not query the database since this IQueryable is accessed.

The IQueryable collection can be accessed through iteration or collection casting (such as IList, Array, ...).

/// This will yield item by item trough the loop.
IQueryable followers = /* linq expression */
foreach (var follower in followers)
{
   // ...
}

The chunk above has a tiny better performance.

IQueryable followers = /* linq expression */
IList list = followers.ToList(); // At this point, the query is executed in the database server
foreach (var follower in list)
{
   // ...
}

While this apporach is more safe.
It is a common practice to cast an IQueryable to an IList or similar to prevent concurrency issues, thread troubles, etc.

The important thing is to "seek" the IQueryable once all the actions on the query are done (filtering, sorting, ...).

Having an IQueryable like so

IQueryable followers = project.Followers;

you can now add actions to the IQueryable with no memory or performance cost.

followers = followers.Where(/* Any Func<Type, bool> action here*/);
followers = followers.OrderBy(/* Property KeySelector... */);

Once all the query is built, the query can be executed.

IList realDataInMemory = followers.ToList();

If you call the #ToList method at the first step.

IList followers = project.Followers.ToList();

the next Linq expressions will be executed to the in-memory collection.

Related