Должен ли я вызвать ToList () внутри foreach C# - PullRequest
1 голос
/ 07 апреля 2020

Этот код нормальный?

Должен ли я вызвать ToList (). Если да, то почему?

Это структура сущности. Или это не имеет значения, и я не могу позвонить в список?

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 ]

2 голосов
/ 07 апреля 2020

ToList существует, чтобы избежать попадания в коллекцию, измененную при повторении ошибки времени выполнения. ToList() делает нетерпеливую копию коллекции, а затем вы перебираете ее, удаляя элементы из оригинального источника project.Followers.

Это выглядит несколько странно, но именно поэтому ToList присутствует.

1 голос
/ 07 апреля 2020

Хорошо, если вы используете Entity Framework (из тегов).
Когда вы выполняете выражение Linq, вы получаете коллекцию IQueryable. Это IQueryable не является правдивой коллекцией, хранящейся в памяти со всеми записями, извлеченными из БД, это своего рода утверждение, куда обращаться к серверу базы данных. Я имею в виду, что вы не будете запрашивать базу данных, так как к этому IQueryable обращаетесь.

Доступ к коллекции IQueryable можно получить с помощью итерации или приведения к ней (например, IList, Array, ...).

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

Вышеупомянутый блок имеет чуть лучшую производительность.

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

Хотя это устройство более безопасно.
Обычная практика - бросать IQueryable на IList или аналогичный для предотвращения проблем параллелизма, проблем с потоками и т. Д. c.

Важным моментом является "поиск" IQueryable после выполнения всех действий в запросе. (фильтрация, сортировка, ...).

Имея IQueryable примерно так

IQueryable followers = project.Followers;

, теперь вы можете добавлять действия к IQueryable без затрат памяти или производительности.

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

Как только весь запрос построен, запрос может быть выполнен.

IList realDataInMemory = followers.ToList();

Если вы вызываете метод #ToList на первом шаге.

IList followers = project.Followers.ToList();

следующие Linq выражения будут выполняться в коллекции в памяти.

...