.NET Tips and Tricks

Blog archive

Create Iterators Easily with the Yield Keyword

This tip is for C# developers only, unfortunately -- but it's the easiest way in the world to create an iterator. An iterator is any method that returns the "next item" in a series. The issue with an iterator is that you have to return a value when called and then pick up at the "next item" when called again.

The simplest iterator in the world is one that just counts from zero on up. In this example, for instance, x would first be set to 0 and then 1 and then 2 and then... you get the picture:

int res;
foreach (int i in Counter())
{
  res = i;
}

Implementing that Counter method is easy if you use yield: Just insert the word "yield" at the start of your return statement to return the value and then pause your method at that statement until the next time it's called. When your method is called, your code will continue on from the statement following the yield statement.

The only wrinkle is that the method must appear in a method that's part of some iterator interface (e.g. IEnumerable). That means, to use the yield statement in the easiest way possible (and, when you're talking about the yield statement, you're aiming for "easiest way possible") you need to declare your method's return type as IEnumerable and call your method inside a foreach block. A version of the Counter method that would go from 0 to 2 would look like this:

public  System.Collections.IEnumerable Counter()
{
 yield return 0;
 yield return 1;
 yield return 2;
}

Each time the Counter method is called, the yield return statement will return the value and then wait to be called again before it will go on to the next statement.

A more complicated version would count up from 0 to the largest possible value that an int supports:

public System.Collections.IEnumerable CounterInfinite()
{
  int i = 0;
  while (i < int.MaxValue)
  { 
   yield return i;
   i += 1;
  }
}

But the principle remains the same: Whenever your code is called, "yield return" something and then, in the next line of code, go on to get the "next one." If, in a Customers object, you wanted to create a property called Orders that lest a developer loop through all of the Orders for a the customer, you could use the yield keyword. In the property's getter, you would retrieve a DataSet and loop through the rows, returning an Order object created from the row at each yield return.

Here's similar code using LINQ to keep it short. The yield return inside the foreach loop returns an Order object and then waits to be called again before going through the loop to get the next Order:

public IEnumerable<Order> Orders
{
  get
  {
    northwndEntities dc = new northwndEntities();
    var res = from o in dc.Orders
              where o.CustomerID == this.CustomerId
              select o;

    foreach (Order o in res)
    {
      yield return o;
    }
  }
}

A developer can now process your collection with code like this:

foreach (Order o in cust.Orders)
{
  //do something with an order
}

Posted by Peter Vogel on 06/20/2011


comments powered by Disqus

Featured

Subscribe on YouTube