Использование метода LINQ First() показывает предупреждение Resharper о «Возможной многократной итерации IEnumerable»

#c# #linq #resharper

#c# #linq #перетачиватель

Вопрос:

У меня есть такой код, как этот:

Person FirstPerson = personsEnumerable .Первый ();

, где personsEnumerable IEnumerable<Person>

Теперь Resharper подчеркивает переменную personsEnumerable и говорит «Возможная итерация IEnumerable». Я понимаю, что означает это предупреждение из других вопросов здесь, на SO, но мне интересно, почему оно показывает это в моем примере? Я думаю, что First() возвращает первый элемент, и нет необходимости повторять коллекцию вообще?

Является ли это «общим» предупреждающим сообщением, которое неприменимо в моем случае (и я могу его проигнорировать), или я не понимаю, как на самом деле работает First() ?

Комментарии:

1. «Я думаю, что First() возвращает первый элемент, и нет необходимости повторять коллекцию вообще» Даже если вам нужен только первый, запрос должен быть выполнен. Тем не менее, я предполагаю, что вы обращаетесь personsEnumerable к нему несколько раз.

2. Покажите нам остальную часть кода. Вы повторяете последовательность дважды, что может означать избыточный поиск данных.

Ответ №1:

Да, он возвращает первый элемент, но все равно создает перечислитель для получения этого первого элемента.Вы могли бы добавить ToArray или ToList после Where , чтобы предотвратить это. Однако, если вы хотите просто получить первый элемент, вы можете использовать перегруженную версию First , для которой требуется Func делегат, и вы можете удалить Where .

Ответ №2:

Рассмотрим этот код:

 var personsEnumerable = peopleList.OrderBy(p => p.Age);
var firstPerson = personsEnumerable.First();
foreach (var p in personsEnumerable)
{
    // whatever
}
 

Первая строка кода настраивает порядок сортировки списка и создания результатов, но на самом деле она ничего не делает, пока вы не попытаетесь ее перечислить. Вторая строка кода, то в конечном итоге будет выполнена сортировка. Таким образом, хотя вы не перечисляете весь результат целиком, вы выполняете код для получения результата. И в некотором роде это повлекло бы за собой выполнение всей тяжелой работы.

foreach Цикл снова выполнит сортировку, прежде чем фактически перечислит результаты.

Комментарии:

1. интересно, является ли personsEnumerable . Any() также будет выполнять сортировку?

2. @GregorValentin: Да.

3. спасибо, приятно это знать! из msdn: «Перечисление источника прекращается, как только результат может быть определен». Так что, имо, в этом случае вы можете проигнорировать предупреждение.

4. @GregorValentin: Вы, вероятно, не захотите игнорировать это предупреждение. В приведенном выше случае, если вы заменили First() на Any() , вызов Any() повлечет за собой стоимость сортировки. И то же самое сделал бы тот foreach . Не проблема, если в нем всего несколько элементов, но если peopleList в нем миллион элементов, вы определенно заметите разницу.

5. Спасибо за обсуждение. Очень полезно!