Iterators in C#

In the previous article we have discussed on Enumerable classes and enumerators and the difference between IEnumerator and IEnumerable Interface in C#. You can understand Enumerators here.

C# language provides a construct for creating Enumerators and Enumerables in simpler way and that is Iterator.By using Iterators, compiler will create Enumerators and Enumerables for you. You can use the enumerators and enumerables generated by iterators wherever you would use manually coded enumerators orenumerables.Iterators require the System.Collections.Generic namespace.

Let’s look at below example.

The following method declaration is another version that produces the same result:
Return an enumerator that returns strings.


you might have the feeling that something is different about this code. It doesn’t seem quite right. What exactly does the yield return statement do?

For example, in the first version, if the method returns on the first yield return statement, then the last two statements can never be reached. If it doesn’t return on the first statement, but continues through to the end of the method, then what happens to the values?

And in the second version, if the yield return statement in the body of the loop returns on the first iteration, then the loop will never get to any subsequent iterations. And besides all that, an enumerator doesn’t just return all the elements in one shot—it returns a new value with each access of the Current property. So, how does this give you an enumerator? Clearly this code is different from anything shown before.

Let’s understand the iterator blocks and yield statements to answer all these questions.

Iterator Blocks:

An iterator block is a code block with one or more yield statements. There are 3 types of Iterator blocks.

  • A method body
  • An accessor body
  • An operator body

In regular code blocks, the first statement in the block is executed, followed by the subsequent statements, and eventually control leaves the block but in iterator block,it describes the behavior of the enumerator class you want the compiler to build for you and it describes how to enumerate the elements.

Iterator blocks have two special statements:
• The yield return statement specifies the next item in the sequence to return.
• The yield break statement specifies that there are no more items in the sequence.

You can have the iterator produce either an enumerator or an enumerable depending on the return type you use for the iterator block.

Using an Iterator to Create an Enumerator:

Output:

black
red
white

Description:

  • Method Color is an iterator block that produces a method that returns an enumerator for class MyClass.
  • MyClass also implements method GetEnumerator, which just calls Color, and returns the enumerator that Color returns to it.
  • In Main, you can use an instance of the class directly in the foreach statement since the class implements GetEnumerator and is therefore enumerable.

Using an Iterator to Create an Enumerable:

Output:

black red white black red white

Description:

  • In the previous example, iterator method Color returned an IEnumerator, and MyClass implemented method GetEnumerator by returning the object created by Color.
  • In this example, the iterator method Color returns an IEnumerable rather than an IEnumerator. MyClass, therefore,implements its GetEnumerator method by first calling method Colors to get the enumerable object and then calling that object’s GetEnumerator method and returning its results.
  • Notice that in the foreach statement in Main, you can either use an instance of the class or call Color directly, since it returns an enumerable.

Common Iterator Patterns

Mainly there are 2 Iterator Patterns.
1.Enumerator Iterator Patterns
2.Enumerable Iterator Patterns
When you implement an iterator that returns an enumerator, you must make the class enumerable by implementing GetEnumerator

    • In a class, when you implement an iterator that returns an enumerable, you can make this class itself enumerable.

− If you implement GetEnumerator, make it call the iterator method to get an instance of the automatically generated class that implements IEnumerable.Next, return the enumerator built by GetEnumerator from this IEnumerable object
− If you decide against making the class itself enumerable, by not implementing GetEnumerator, you can still use the enumerable returned by the iterator, by calling the iterator method directly.

Creating Multiple Enumerables

Output:

Iterators as Properties:

Output:

Description:

In the above example,

  • It uses iterators to produce a class with two enumerators.
  • It shows how iterators can be implemented as properties rather than methods.
  • The code declares two properties that define two different enumerators. The GetEnumerator method returns one or the other of the two enumerators, depending on the value of the Boolean variable _listFromUVtoIR. If _listFromUVtoIR is true, then the UVtoIR enumerator is returned. Otherwise, the IRtoUV enumerator is returned.

Behind the Scenes with Iterators in C#

The enumerator class generated by the compiler is a state machine with four states:
• Before: The initial state before the first call to MoveNext.
• Running: The state entered when MoveNext is called. In this state, the enumerator determines and sets the position for the next item. It exits the state when it encounters a yield return, a yield break, or the end of the iterator body.
• Suspended: The state where the state machine is waiting for the next call to MoveNext.
• After: The state where there are no more items to enumerate.

Summary:

In this article, we have discussed:

  • Iterators in C#
  • Iterator Blocks
  • Yield Statements
  • Using an Iterator to Create an Enumerator
  • Using an Iterator to Create an Enumerable
  • Common Iterator Patterns
  • Creating Multiple Enumerables
  • Iterators As Properties
  • Behind the Scenes with Iterators
  • Iterator StateMachine
  • An Iterator state machine

Leave a Reply

Your email address will not be published. Required fields are marked *