Является ли foreach чисто "синтаксическим сахаром"?

Компилятор компилирует цикл foreach в нечто вроде цикла for когда foreach используется с массивом. И компилятор компилирует foreach цикл в нечто вроде в while цикла, когда foreach используется с IEnumerable или IEnumerable<T>. Значит ли это, что foreach - это чисто syntactic sugar? Или в этом есть что-то сложное?

Знает ли CLR о foreach? Есть ли что-то специально разработанное для foreach в коде MSIL?

Ответ 1

Это чисто синтаксический сахар, в котором вы можете получить такое же поведение без него, да. Многие другие вещи одинаковы... for, while и т.д. Чтобы неверно процитировать Архимеда: "Дайте мне if и goto, и я переведу код..."

Нет, у CLR нет понятия foreach.

Ответ 2

Это синтаксический сахар. Однако обратите внимание, что foreach работает, вызывая GetEnumerator(), затем MoveNext() до тех пор, пока не будет возвращен какой-либо дополнительный элемент, а затем всегда вызывается Dispose() на счетчике, который он ранее получил. Если вы хотите сделать это одинаково, не забывайте, что Dispose()!

Кроме того, CLR выполняет некоторые трюки, связанные с получением перечислителя. См. здесь и здесь, например.

Ответ 3

foreach является внутренним просто циклом while, который вызывает методы в IEnumerator.

Ответ 4

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

то есть.

Foreach(String s in List<string>)
{
   s = "f";  //this will throw an error.
}

Ответ 5

Да, это чисто сахар. Следующий код

var MyList = new List<int>() { 10 , 20 , 30 , 40, 50} ;  
foreach(int i in MyList) 
{
    Console.WriteLine(i);
}

переводится в компилятор как:

Ienumrator<int> rator = MyList.GetEnumrator();

try
{
   while(rator.MoveNext())
   {
       int i = rator.Current; 
       Console.WriteLine(i); 
   }
}
finally
{
    rator.Dispose()
}