It doesn’t use an anonymous function, no. Basically the compiler converts the code into something broadly equivalent to the while loop you’ve shown here.
foreach
isn’t a function call – it’s built-into the language itself, just like for
loops and while
loops. There’s no need for it to return anything or “take” a function of any kind.
Note that foreach
has a few interesting wrinkles:
- When iterating over an array (known at compile-time) the compiler can use a loop counter and compare with the length of the array instead of using an
IEnumerator
foreach
will dispose of the iterator at the end; that’s simple forIEnumerator<T>
which extendsIDisposable
, but asIEnumerator
doesn’t, the compiler inserts a check to test at execution time whether the iterator implementsIDisposable
- You can iterate over types which don’t implement
IEnumerable
orIEnumerable<T>
, so long as you have an applicableGetEnumerator()
method which returns a type with suitableCurrent
andMoveNext()
members. As noted in comments, a type can also implementIEnumerable
orIEnumerable<T>
explicitly, but have a publicGetEnumerator()
method which returns a type other thanIEnumerator
/IEnumerator<T>
. SeeList<T>.GetEnumerator()
for an example – this avoids creating a reference type object unnecessarily in many cases.
See section 8.8.4 of the C# 4 spec for more information.