Reputation: 5232
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
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