17

The compiler compiles a foreach loop into something like a for loop when the foreach is used with an array. And the compiler compiles a foreach loop into something like a while loop when the foreach is used with an IEnumerable or IEnumerable<T>. So does this mean foreach is purely syntactic sugar? Or is there anything sophisticated about it?

Does the CLR know about foreach? Is there anything specifically designed for foreach in the MSIL code?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Cui Pengfei 崔鹏飞
  • 8,017
  • 6
  • 46
  • 87

5 Answers5

29

It's purely syntactic sugar in that you could obtain the same behaviour without it, yes. Many other things are the same... for, while etc... To misquote Archimedes: "Give me if and goto, and I will move the code..."

No, the CLR doesn't have any concept of foreach.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
10

It is syntactic sugar. However, note that foreach works by calling GetEnumerator(), then MoveNext() until there is no further item returned and then always calls Dispose() on the enumerator it previously obtained. If you want to do it the same way, don't forget that Dispose()!

Also, the CLR does some tricks related to getting the enumerator. See here and here, for example.

Daniel Rose
  • 17,233
  • 9
  • 65
  • 88
2

Yes, it is purely sugar. The following code

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

is translated in compiler as:

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

try
{
   while(rator.MoveNext())
   {
       int i = rator.Current; 
       Console.WriteLine(i); 
   }
}
finally
{
    rator.Dispose()
}
FutureCake
  • 2,614
  • 3
  • 27
  • 70
2

foreach is internally just a while loop that calls the methods in IEnumerator.

dan04
  • 87,747
  • 23
  • 163
  • 198
0

It is not just syntactic sugar as the items in a foreach loop are immutable (unchangeable). The reason for this, as Daniel so kindly pointed out, is that most collections will use an enumerator in a foreach, and it is the enumerator that has the restriction of not letting you update the contents of the list while it is being enumerated.

i.e.

Foreach(String s in List<string>)
{
   s = "f";  //this will throw an error.
}
Mark Hosang
  • 501
  • 5
  • 21
  • interesting, then how can we mimic this kind of behavior by using a for or while loop? – Cui Pengfei 崔鹏飞 Apr 28 '11 at 14:07
  • now that i think it again, it seems wrong. this is just a man-made rule that helps to decrease misunderstanding. – Cui Pengfei 崔鹏飞 Apr 28 '11 at 14:12
  • It is syntactic sugar, and it's not quite the definition of immutable. The variable itself cannot be modified, but the object it references can be changed in whatever way the object supports (although not in the case of an already immutable type, of course). – Anthony Pegram Apr 30 '11 at 04:56
  • 1
    -1: This will throw an error because foreach uses the enumerator from List. That enumerator throws an error if you continue to use it after modifying the List. It's not something special to foreach. – Daniel Rose Apr 30 '11 at 10:46
  • @daniel you are correct in that it is actual the enumerator that throws the error, but in response to the OP question, i was hoping to show that there is a fundamental difference in using a foreach to a normal for loop that will intend cause errors depending on how you use it. – Mark Hosang May 04 '11 at 03:49
  • True. However, that is because the enumerator in List is designed that way. If you use foreach on a different collection, modifying the elements may be ok. So you should clarify what actually occurs in your post. – Daniel Rose May 04 '11 at 07:03
  • i was under the assumption that all iCollection implemented iEnumerate [link](http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx), thus any non-custom collection would thus be using an enumerator. Are there any cases you know off the top of your head that don't use iEnumerator? – Mark Hosang May 05 '11 at 14:40