Разница между циклами foreach и for над классом IEnumerable в C # - PullRequest
13 голосов
/ 04 сентября 2008

Мне сказали, что есть разница в производительности между следующими блоками кода.

foreach (Entity e in entityList)
{
 ....
}

и

for (int i=0; i<entityList.Count; i++)
{
   Entity e = (Entity)entityList[i];
   ...
}

где

List<Entity> entityList;

Я не ожидаю CLR, но из того, что я могу сказать, они должны сводиться в основном к одному и тому же коду. У кого-нибудь есть конкретные (чёрт, я бы взял упакованную грязь) доказательства, так или иначе?

Ответы [ 7 ]

10 голосов
/ 04 сентября 2008

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

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

9 голосов
/ 04 сентября 2008

Здесь - хорошая статья, показывающая разницу между двумя контурами.

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

6 голосов
/ 04 сентября 2008

Пример foreach примерно соответствует этому коду:

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

Здесь есть две стоимости, которые регулярный цикл for не должен оплачивать:

  1. Стоимость выделения объекта-перечислителя entityList.GetEnumerator ().
  2. Стоимость двух вызовов виртуальных методов (MoveNext и Current) для каждого элемента списка.
3 голосов
/ 04 сентября 2008

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

Неисчислимое количество НЕ.

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

Спорный вопрос, поскольку в IEnumerable нельзя ссылаться на элементы по индексу.

Так что если вы хотите заблокировать списки и массивы, вы можете получить небольшое увеличение производительности.

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

1 голос
/ 04 сентября 2008

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

0 голосов
/ 13 января 2014
For Loop
for loop is used to perform the opreration n times
for(int i=0;i<n;i++)
{
l=i;
}
foreach loop

int[] i={1,2,3,4,5,6}
foreach loop is used to perform each operation value/object in IEnumarable 
foreach(var k in i)
{
l=k;
}
0 голосов
/ 04 сентября 2008

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

<code>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 каждый раз, когда мне нужны все предметы, и мне нет дела до индекса предмета. Если я не работаю со всеми элементами или мне действительно нужно знать индекс, я использую для . Единственный раз, когда я увидел, что это вызывает серьезную озабоченность, - это структуры типа связанных списков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...