(обновление)
На самом деле - есть один сценарий, в котором конструкция for
более эффективна; зацикливание на массиве. Компилятор / JIT имеет оптимизацию для этого сценария , пока вы используете arr.Length
в условии :
for(int i = 0 ; i < arr.Length ; i++) {
Console.WriteLine(arr[i]); // skips bounds check
}
В этом очень специфическом случае он пропускает проверку границ, поскольку уже знает, что он никогда не выйдет за пределы. Интересно, что если вы «поднимете» arr.Length
, чтобы попытаться оптимизировать его вручную, вы предотвратите это:
int len = arr.Length;
for(int i = 0 ; i < len ; i++) {
Console.WriteLine(arr[i]); // performs bounds check
}
Однако для других контейнеров (List<T>
и т. Д.) Подъем вполне оправдан в качестве ручной микрооптимизации.
(окончание обновления)
Ни; цикл for в любом случае рассматривается как цикл while под капотом.
Например, 12.3.3.9 из ECMA 334 (определенное назначение) диктует, что цикл for:
for ( for-initializer ; for-condition ; for-iterator ) embedded-statement
по существу эквивалентно (с точки зрения Определенное присваивание (не совсем то же самое, что сказать "компилятор должен генерировать этот IL")) как:
{
for-initializer ;
while ( for-condition ) {
embedded-statement ;
LLoop:
for-iterator ;
}
}
с операторами продолжения, которые нацелены
заявление для перевода в
заявления goto, нацеленные на ярлык
Lloop. Если условие не указано
из заявления, то
оценка определенного задания
поступает так, как если бы условия были
заменено истинным в приведенном выше
расширение.
Теперь, это не значит, что компилятор должен делать то же самое, но на самом деле это в значительной степени делает ...