1
static void Main()
{
    DaysOfTheWeek days = new DaysOfTheWeek();

    foreach (string day in days)
    {
        Console.Write(day + " ");
    }

    // Output: Sun Mon Tue Wed Thu Fri Sat  
    Console.ReadKey();
}

public class DaysOfTheWeek : IEnumerable
{
    private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

    public IEnumerator GetEnumerator()
    {
        for (int index = 0; index < days.Length; index++)
        {
            // Yield each day of the week.  
            yield return days[index];
        }
    }
}

What happens in the foreach loop. Does it calls the GetEnumerator function, for every iteration or the foreach is replaced by the GetEnumerator function? Does the complexity goes to O(n2) in this case?

Marc
  • 3,905
  • 4
  • 21
  • 37
Praburaj
  • 613
  • 8
  • 21
  • 3
    Possible duplicate of [In c#, is foreach purely a “syntactic sugar”? Or is there anything deeper about it?](http://stackoverflow.com/questions/5816776/in-c-is-foreach-purely-a-syntactic-sugar-or-is-there-anything-deeper-about) – Janne Matikainen Dec 21 '16 at 07:23
  • I don't see how that answers the question @Janne – Patrick Hofman Dec 21 '16 at 07:28

3 Answers3

4

The yield return creates a state machine that basically returns a value and then waits until the calling party (your first foreach) requests the next item in the enumerator.

IEnumerable is just an interface that describes a way to iterate over a set of data, the IEnumerator in there is the interface that describes how to call the iterator.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • It seems the complexity goes to O(n2)? Isn't it? – Praburaj Dec 21 '16 at 07:26
  • No, why should it be O(n2)? Just O(n) would do. – Patrick Hofman Dec 21 '16 at 07:30
  • The enumerator of the list/array uses an int to point to the element that is requested. For each loop in `foreach`, `MoveNext` is called and just increments a pointer. Lookups in these structures are O(1). Ref: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,1140 – Caramiriel Dec 21 '16 at 07:32
  • A `foreach` iterates over all items, so it is always `O(n)`, right? – Patrick Hofman Dec 21 '16 at 07:33
2

There is a nice desription of yield return in this blog post:

https://www.kenneth-truyers.net/2016/05/12/yield-return-in-c/

Basically it says that

Each iteration of the foreach loop calls the iterator method. When the yield return statement is reached the value is returned, and the current location in code is retained. Execution is restarted from that location the next time that the iterator function is called.

As the location is retained for the next call, I think complexity should be O(n) rather than O(n2).

wkl
  • 1,896
  • 2
  • 15
  • 26
0

No, the GetEnumerator will not be called for every iteration. If you compile your code in release configuration and check the IL code generated you will end up with code like this.

IEnumerator enumerator2 = days.GetEnumerator();
try
{
    while (enumerator2.MoveNext())
    {
        Console.Write((string)enumerator2.Current + " ");
    }
}
finally
{
    IDisposable disposable = enumerator2 as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

So basically you could write that same code yourself, foreach is just syntactic sugar to help you write less code.

Janne Matikainen
  • 5,061
  • 15
  • 21