Пример кода Resharper для объяснения "Возможное множественное перечисление IEnumerable"
Иногда Resharper предупреждает о:
Возможная множественная перечисление IEnumerable
Здесь вопрос SO о том, как справиться с этой проблемой, а также сайт ReSharper также объясняет вещи здесь. В нем есть пример кода, который говорит вам об этом:
IEnumerable<string> names = GetNames().ToList();
Мой вопрос об этом конкретном предположении: не приведет ли это к повторному перечислению через коллекцию дважды в каждой из двух циклов?
Ответы
Ответ 1
GetNames()
возвращает IEnumerable
. Поэтому, если вы сохраните этот результат:
IEnumerable foo = GetNames();
Затем каждый раз, когда вы перечисляете foo
, метод GetNames()
вызывается снова (не буквально, я не могу найти ссылку, которая правильно объясняет детали, но см. IEnumerable.GetEnumerator()
).
Resharper видит это и предлагает вам сохранить результат перечисления GetNames()
в локальной переменной, например, материализуя его в списке:
IEnumerable fooEnumerated = GetNames().ToList();
Это гарантирует, что результат GetNames()
будет указан только один раз, если вы ссылаетесь на fooEnumerated
.
Это имеет значение, потому что вы обычно хотите перечислять только один раз, например, когда GetNames()
выполняет (медленный) вызов базы данных.
Поскольку вы внесли материализованный результат в список, теперь не имеет значения, что вы дважды перечисляете fooEnumerated
; вы будете дважды повторяться в списке в памяти.
Ответ 2
GetNames()
не вызывается дважды. Реализация IEnumerable.GetEnumerator()
вызывается каждый раз, когда вы хотите перечислить коллекцию с помощью foreach
. Если в IEnumerable.GetEnumerator()
сделан некоторый дорогостоящий расчет, это может послужить поводом для рассмотрения.
Ответ 3
Я нашел, что у этого есть лучший и простой способ понять несколько перечислений.
С# LINQ: Возможное многократное перечисление IEnumerable
https://helloacm.com/c-linq-possible-multiple-enumeration-of-ienumerable-resharper/
Ответ 4
Да, вы будете перечислять его дважды без всяких сомнений. но дело в том, что если GetNames()
возвращает ленивый запрос linq, который очень дорог для вычисления, тогда он будет вычислять дважды без вызова ToList()
или ToArray()
.