Пример кода Resharper для объяснения " возможного множественного перечисления IEnumerable"


иногда Решарпер предупреждает о:

возможно многократное перечисление IEnumerable

есть так вопрос о том, как справиться с этой проблемой, и сайт ReSharper также объясняет вещи здесь. Он имеет некоторый пример кода, который говорит вам сделать это вместо этого:

IEnumerable<string> names = GetNames().ToList();

мой вопрос касается этого конкретного предложения: не приведет ли это к перечислению через коллекцию дважды в циклах 2 for-each?

4 61

4 ответа:

GetNames() возвращает IEnumerable. Так что если вы храните этот результат:

IEnumerable foo = GetNames();

тогда каждый раз, когда вы перечисляете foo на GetNames() метод вызывается снова (не буквально, я не могу найти ссылку, которая правильно объясняет детали, но см. IEnumerable.GetEnumerator()).

Решарпер видит это, и предлагает вам сохранить результат о перечислении GetNames() в локальной переменной, например, материализуя ее в a список:

IEnumerable fooEnumerated = GetNames().ToList();

это позволит убедиться, что GetNames() результат перечисляется только один раз, если вы ссылаетесь на fooEnumerated.

это важно, потому что вы обычно хотите перечислить только один раз, например, когда GetNames() выполняет (медленный) вызов базы данных.

потому что ты овеществленный результаты в списке, это больше не имеет значения, что вы перечисляете fooEnumerated дважды; вы будете повторять список в памяти дважды.

Я обнаружил, что это лучший и самый простой способ понять несколько перечислений.

C# LINQ: возможно многократное перечисление IEnumerable

https://helloacm.com/c-linq-possible-multiple-enumeration-of-ienumerable-resharper/

GetNames() не вызывается дважды. Реализация IEnumerable.GetEnumerator() вызывается каждый раз, когда вы хотите перечислить сбора с foreach. Если в пределах IEnumerable.GetEnumerator() некоторые дорогостоящие расчеты сделаны это может быть причиной для рассмотрения.

Да, вы будете перечислять его дважды без сомнения. но дело в том, если GetNames() возвращает ленивый запрос linq, который очень дорого вычислить, то он будет вычислять два раза без вызова ToList() или ToArray().