Yield Statement in C#

Many times we need to collect a number of results depending upon certain conditions. For that we need to create some sort of collection object, inserting the output to that collection and then returning that collection. But it can be very cumbersome to do that.

A rather simple way to do that is to use the Yield statement (C# 2,0 onwards). This keyword is used to return items from a loop within a method and retain the state of the method through multiple calls.

Yield returns IEnumerator or generic IEnumerator<T>.

public static IEnumerator<int> GetCounter()
{
      for (int count = 0; count < 10; count++)
      {
          yield return count;
      }
}

This will return the collection IEnumerator<int> which can be used to get the objects returned.

IEnumerator<int> list =  GetCounter();
Console.Write(list.MoveNext() + " "+ list.Current);

There is also the yield break statement. If a yield break statementis hit within a method,execution of that method stops with no  return.Using this, the first method could be rewritten like this;

public static IEnumerator<int> GetCounter()
{
   int max = 10, min = 5;
   while (true)
   {
      if (min >= max)
      {
         yield break;
      }
      yield return min++;
   }
}

Before I go any further, it's worth remembering that an iterator block doesn't just run from start to finish.  When the method is originally called, the iterator is just created. It's only when MoveNext() is called. At that point, execution starts at the top of the method as normal, and progresses as far as the first yield return or yield break statement, or the end of the method. At that point, a Boolean value is returned to indicate whether or not the block has finished iterating. If/when MoveNext()  is called again, the method continues executing from just after the yield return statement.

using System;
using System.Collections.Generic;
class Test
{
    static readonly string Padding = new string(' ', 30);
    static IEnumerator<int> GetNumbers()
    {

        Console.WriteLine("First line of GetNumbers()");

        Console.WriteLine("Just before yield return 0?);

        yield return 10;

        Console.WriteLine("Just after yield return 0?);

 

        Console.WriteLine("Just before yield return 1?);

        yield return 20;

        Console.WriteLine("Just after yield return 1");
    }    
    static void Main()
    {

           Console.WriteLine("Calling GetNumbers()");

           IEnumerator<int> iterator = GetNumbers();

           Console.WriteLine("Calling MoveNext()");

           bool more = iterator.MoveNext();

Console.WriteLine("Result={0}; Current={1}", more, iterator.Current);
 

           Console.WriteLine("Calling MoveNext() again");

           more = iterator.MoveNext();

Console.WriteLine("Result={0}; Current={1}", more, iterator.Current);
 

           Console.WriteLine("Calling MoveNext() again");

           more = iterator.MoveNext();

           Console.WriteLine("Result={0} (stopping)", more);
    }
}

—–Result
Calling GetNumbers()
Calling MoveNext()…
                              First line of GetNumbers()
                              Just before yield return 0
Result=True; Current=10
Calling MoveNext() again…
                              Just after yield return 0
                              Just before yield return 1
Result=True; Current=20
Calling MoveNext() again…
                              Just after yield return 1
Result=False (stopping)

This is very useful in LINQ query expressions in C# 3.0 as this provides the iterations required in LINQ queries.

Suppose there is CustomerCollection Class having customers list (IEnumerable<Customer> _customers)

public class CustomerCollection : IEnumerable<Customer>

This class is being used in LINQ query to iterate through the customer object contained in its list (_customers) and thus is supposed to implement GetEnumerator method as:

public IEnumerator<Customer> GetEnumerator()
{

    foreach (Customer customer in _customers)
        yield return customer;   
}

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

Leave a Reply