Lijin Durairaj
Lijin Durairaj

Reputation: 5232

How is the GetEnumerator method get invoked in a foreach loop in C#?

I was going through Iterator pattern and got a little confused when i stumpled upon logic i found in the sample code

class MonthCollection : IEnumerable
        {

          public string[] months = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};

            public IEnumerator GetEnumerator()
            {
                // Generates values from the collection
                foreach (string element in months)
                    yield return element;
            }
        }

        static void Main()
        {

            MonthCollection collection = new MonthCollection();
            // Consumes values generated from collection's GetEnumerator method
            foreach (string n in collection)
                Console.Write(n + " ");
            Console.WriteLine("\n");
        }

in this code, the normal way to access the Array to strings would be to call the months variable like this in the foreach statement

MonthCollection collection = new MonthCollection();
foreach (string n in collection.months){ }

but i could not understand how is the foreach getting access to the collection without even calling the months variable directly

MonthCollection collection = new MonthCollection();
foreach (string n in collection){}

UPDATE 1

what i couldnt understand is how can i access the variable months without calling it like this in the above class

static void Main()
        {

            MonthCollection collection = new MonthCollection();
            // Consumes values generated from collection's GetEnumerator method
            foreach (string n in collection.months)
                Console.Write(n + " ");
            Console.WriteLine("\n");
        }

instead of like this

 MonthCollection collection = new MonthCollection();
               method
                foreach (string n in collection)
                    Console.Write(n + " ");
                Console.WriteLine("\n");

Upvotes: 3

Views: 2030

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726539

foreach loop does not require a collection, all it needs is a an object with a GetEnumerator() method returning IEnumerator, which in your case comes with IEnumerable implementation.

C# compiler produces the remaining "magic" - a hidden temporary variable to reference the enumerator object, the code to start enumeration, the code to get each item, and the code to see when enumeration is over.

In your case C# relies on your implementation to get to the content of the months array using another piece of "magic" - the yield return construct. This construct lets you implement GetEnumerator() without writing a separate class for it. The construct is converted to a class with a state machine, letting you "return" objects from the middle of a loop, and then restart back where it was when the next item is requested from the iterator.

The objects returned from yield return do not have to come from a collection. You can even mix objects from a collection with other objects, for example

public IEnumerator GetEnumerator() {
    // Generates values from the collection
    foreach (string element in months) {
        yield return element + " will start soon!";
        yield return element;
        yield return element + " has ended.";
    }
}

foreach loop access variable months indirectly, through your code that implements GetEnumerator().

Upvotes: 3

Related Questions