Подтвердить что ты не робот

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

Иногда Resharper предупреждает о:

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

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

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

Мой вопрос об этом конкретном предположении: не приведет ли это к повторному перечислению через коллекцию дважды в каждой из двух циклов?

4b9b3361

Ответ 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() сделан некоторый дорогостоящий расчет, это может послужить поводом для рассмотрения.

Ответ 4

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