Различие между foreach и для циклов по классу IEnumerable в C#

Время от времени проблема была accuracy.txt пустой, из-за чего цикл никогда не выполнялся и user_new никогда не определялся. Спасибо @Joe Allen за ответ.

13
задан Craig 4 September 2008 в 17:20
поделиться

6 ответов

foreach создает экземпляр перечислителя (возвратился из GetEnumerator), и тот перечислитель также сохраняет состояние на всем протяжении цикла foreach. Это тогда неоднократно призывает к Следующему () объект на перечислителе и выполняет Ваш код для каждого объекта, который это возвращает.

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

10
ответ дан 1 December 2019 в 20:44
поделиться

foreach образец примерно соответствует этому коду:

using(IEnumerator<Entity> e = entityList.GetEnumerator()) {
    while(e.MoveNext()) {
        Entity entity = e.Current;
        ...
    }
}

существует два издержек здесь, которые не должен оплачивать постоянный клиент для цикла:

  1. стоимость выделения перечислителя возражают entityList. GetEnumerator ().
  2. стоимость двух виртуальных вызовов методов (MoveNext и Текущий) для каждого элемента списка.
6
ответ дан 1 December 2019 в 20:44
поделиться

Одна суть упущена здесь: Список имеет свойство Count, он внутренне отслеживает то, сколько элементов находится в нем.

IEnumerable НЕ ДЕЛАЕТ.

, Если Вы программируете к интерфейсу IEnumerable и используете метод расширения количества, он перечислит только для подсчета элементов.

спорный вопрос А, хотя с тех пор в IEnumerable Вы не можете обратиться к объектам индексом.

Поэтому, если Вы хотите привязаться к Спискам и Массивам, можно получить маленькие увеличения производительности.

, Если Вы хотите использование гибкости foreach и программу к IEnumerable. (разрешение использования linq и/или возврата урожая).

3
ответ дан 1 December 2019 в 20:44
поделиться

Я думаю одна возможная ситуация, где Вы могли бы добираться, увеличение производительности состоит в том, если размер перечислимого типа и условие цикла являются константой; например:

const int ArraySize = 10;
int[] values = new int[ArraySize];

//...

for (int i = 0; i 

В этом случае, в зависимости от сложности тела цикла, компилятор мог бы быть в состоянии заменить цикл встроенными вызовами. Я понятия не имею, делает ли компилятор.NET это, и это имеет ограниченную утилиту, если размер перечислимого типа является динамичным.

Одна ситуация, где foreach мог бы работать лучше, со структурами данных как связанный список, где произвольный доступ означает пересекать список; перечислитель, используемый foreach, вероятно, выполнит итерации одного объекта за один раз, делая каждый доступ O (1), и полный цикл O (n), но называя индексатор означает запускаться в голове и находить объект в правильном индексе; O (N) каждый цикл для O (n^2).

Лично я обычно не волнуюсь об этом и использование foreach никакое время, я нуждаюсь во всех объектах и не забочусь об индексе объекта. Если я не работаю со всеми объектами, или я действительно должен знать индекс, я использую для. Единственное время я видел, что он был большим беспокойством, со структурами как связанные списки.

0
ответ дан 1 December 2019 в 20:44
поделиться

С точки зрения выделений было бы лучше посмотреть это сообщение в блоге . Это показывает в точно, при каких обстоятельствах перечислитель выделяется на "куче".

1
ответ дан 1 December 2019 в 20:44
поделиться

Здесь хорошая статья, которая показывает различия IL между этими двумя циклами.

Foreach технически медленнее однако намного легче использовать и легче читать. Если производительность не очень важна, я предпочитаю цикл foreach по для цикла.

9
ответ дан 1 December 2019 в 20:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: