Skip to content

Iterators

Mario Gutierrez edited this page Jan 7, 2017 · 1 revision

Note: these examples don't use the generic versions. Use the generic versions to prevent penalties incurred by auto-boxing.

public interface IEnumerable
{
  IEnumerator GetEnumerator(); // Used by the foreach loop.
}

public interface IEnumerator
{
  bool MoveNext(); // Advance the cursor position.
  object Current() { get; } // Get the current item.
  void Reset(); // Reset the cursor.
}

public class SomeClass : IEnumerable
{
  // ...
  // This is a special "iterator" method.
  public IEnumerator GetEnumerator()
  {
    for (var i = 0; i < items.Length; ++i)
    {
		 // The compiler automatically generates a nested IEnumerator that
		 // keeps track of execution, and returns items[i] for Current.
		 yield return items[i];
		 // You cannot call Reset on an instance of this generated IEnumerator,
		 // you'll have to get a new instance of it.
    }
  }

  // This is a "named iterator" method.
  public IEnumerator GetReverseEnumerator(string msg)
  {
    Console.WriteLine("Named iterators can receive parameters: " + msg);
    for (var i = items.Length-1; i >= 0; --i)
    {
      yield return items[i];
    }
  }
}

You can use the iterators in a foreach loop.

foreach (Item it in someClass) {}
foreach (Item it in someClass.GetReverseEnumerator()) {}

The 'Yield' Keyword

When you use the yield keyword in a statement, you indicate that the method, operator, or "get" accessor in which it appears is an iterator. Using yield to define an iterator removes the need for an explicit extra class (the class that holds the state for an enumeration, see IEnumerator)

  • yield return - return each element one at a time.
  • yield break - end iteration.

You consume an iterator by using a foreach statement or LINQ query. Each iteration of the foreach loop calls the iterator. When a yield return statement is reached in the iterator method, the expression 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.

yield is not a reserved word and has special meaning only when it is used before a return or break keyword.

An iterator method cannot have any ref or out parameters.

An implicit conversion must exist from the expression type in the yield return statement to the return type of the iterator.

Clone this wiki locally