Разница между циклами foreach и for для класса IEnumerable в C#

StackOverflow https://stackoverflow.com/questions/44220

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

и

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

где

List<Entity> entityList;

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

Здесь есть две затраты, которые обычный цикл for не должен оплачивать:

  1. Стоимость выделения объекта enumerator с помощью EntityList.GetEnumerator().
  2. Стоимость вызовов двух виртуальных методов (MoveNext и Current) для каждого элемента списка.

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

IEnumerable ЭТОГО НЕ ДЕЛАЕТ.

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

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

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

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

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

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

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).

Personally I don't usually worry about it and use foreach any time I need all items and don't care about the index of the item. If I'm not working with all of the items or I really need to know the index, I use for.Единственный раз, когда я мог видеть, что это вызывает большую озабоченность, - это такие структуры, как связанные списки.

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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top