The benefit of the Yield statement was not crystal clear to me when I first encountered it — after all, it was introduced in C# 2.0. I recently revisited the topic with an iterator and instantly saw its value. Before I explain how to use the Yield statement, let’s do a quick review of iterators.

Looking at iterators

MSDN defines an iterator as “a method, get accessor or operator that enables you to support foreach iteration in a class or struct without having to implement the entire IEnumerable interface.” Instead of implementing the IEnumerable interface, an iterator is developed, which simply traverses the data structures in the class. The C# compiler automatically generates the Current, MoveNext, and Dispose methods when it detects the iterator. (These methods are part of the IEnumerable or IEnumerable<T> interface.) The following code snippet shows an iterator in use.

IList<string> SearchIt(IEnumerable<string> pList, string pSearchFor) {

var temp = new List<string>();

foreach (var cur in pList) {

if (cur.StartsWith(pSearchFor))

temp.Add(cur);

}

return temp;

}

The following code shows it in action.

static void Main(string[] args) {

IEnumerable<string> test = new string[]{"Tony", "John", "Timothy", "Anthony", "Julius"};

System.Collections.Generic.IList<string> t = SearchIt(test, "T");

foreach (string j in t) {

Console.WriteLine(j);

} }

It passes in an IEnumerable object and searches for values in it using the specified passed value in the second parameter. A List object is returned thatcontains all of the matches. This demonstrates one of the drawbacks of iterators with the overhead of maintaining state of where you are in a collection. In this case, we loop through the values with a foreach block and compile the matched items. Yield eliminates this problem by making the compiler do the heavy lifting of maintaining the state of the list — that is, where you are in the list.

Using Yield

A good way to see what Yield can do is through a simple example. The following code alters the previous example to use Yield as opposed to creating and populating a List object.

static IEnumerable<string> SearchIt(IEnumerable<string> pList, string pSearchFor)

{

foreach (var cur in pList) {

if (cur.StartsWith(pSearchFor)) yield return cur;

} }

The method uses Yield to add values to the returned string value, and it keeps track of the current location with the passed in list. The following code utilizes the method using Yield.

static void Main(string[] args) {

IEnumerable<string> test = new string[]{"Tony", "John", "Timothy", "Anthony", "Julius"};

IEnumerable<string> t = SearchIt(test, "T");

foreach (string j in t) {

Console.WriteLine(j);

} }

As you can see, Yield is used to return items from a loop within a method and retain the state of the method through multiple calls.

One key point in our example is the amount of code in the Yield example — it is much less than the first example where a List object had to be created and populated. The code iterates through the list of string values and adds matching values to the returned IEnumerable string object. All of the code to add and create the list of matching string values is handled by C#.

Another variation of Yield (the Yield break statement) allows you to halt the processing of values. When the system encounters Yield break, it stops the processing of object values at the current location. The following code snippet inserts a Yield statement for the purposes of the example — basically, one match is found and the code exits.

foreach (var cur in pList) {

if (cur.StartsWith(pSearchFor)) {

yield return cur;

} else {

yield break;

} }

Yield simplifies working with iterators, but it does add overhead with the work assigned to the system. Theoretically, Yield could introduce performance issues, but this can only be revealed by thoroughly testing an application. It is worth noting that Yield can only appear inside an iterator block (which might be used as a body of a method, an operator, or an accessor), but it may not appear in an anonymous method. When used with an expression, it cannot appear in a try or catch block.

There are plenty of other C# features awaiting your use, so dig into the available options to take full advantage of the .NET environment. What are your favorite features of C#/.NET? Let us know in the discussion.