Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# State machine - Yield

0.00/5 (No votes)
17 Jun 2012 1  
C# State machine - Yield

Introduction 

The yield keyword introduced in C# 2.0. The yield keyword allows you to create a state machine iterate through the collection of objects one by one.

Yield is a contextual keyword used in iterator methods in C#. Yield use like following in iterator block

public IEnumerable methodname(params)
{
      foreach(type element in listofElement)
      {
         ...code for processing 
         yield return result;
      }
}

Note: Here IEnumerable can be replace by IEnumerable<T>.

So actually the yield keyword does is "When you process the collection by this keyword in iterator block. It pauses the execution and returns the proceeded element or the current element of the collection. And when you call it again it starts the execution with the next element which in turn becomes the current element for that call. This continues until it reachs the last element of the collection."

Now I am going to show how you how you can gain some performance when you make use of yield keyword.

In this example I am checking each datarow of the datatable weather it is empty or not.

Code With Yield Keyword

static void Main(string[] args)
{
     int[] arr = new int[] { 1, 2, 3 };

     DataTable table = new DataTable();
     table.Columns.Add("ItemName", typeof(string));
     table.Columns.Add("Quantity", typeof(int));
     table.Columns.Add("Price", typeof(float));
     table.Columns.Add("Process", typeof(string));
     //     // Here we add five DataRows.
     // table.Rows.Add("Indocin", 2, 23);
     table.Rows.Add("Enebrel", 1, 10);
     table.Rows.Add(null, null, null);
     table.Rows.Add("Hydralazine", 1, null);
     table.Rows.Add("Combivent", 3, 5);
     table.Rows.Add("Dilantin", 1, 6);

     foreach (DataRow dr in GetRowToProcess(table.Rows))
     {
         if (dr != null)
         {                    
            dr["Process"] = "Processed";
            Console.WriteLine(dr["ItemName"].ToString() + dr["Quantity"].ToString() + " : " + dr["Process"].ToString());
            //bool test = dr.ItemArray.Any(c => c == DBNull.Value);
         }
      }
      Console.ReadLine();
}
private static IEnumerable<datarow>GetRowToProcess(DataRowCollection dataRowCollection)
{
     foreach (DataRow dr in dataRowCollection)
     {
          bool isempty = dr.ItemArray.All(x => x == null || (x!= null && string.IsNullOrWhiteSpace(x.ToString())));

          if (!isempty)
          {
             yield return dr;
             //dr["Process"] = "Processed";
          }
          else
          {
             yield return null;
             //dr["Process"] = " Not having data ";
          }
          //yield return dr;
     }
}

Code Without Yield Keyword

private static IList<datarow> GetRowToProcess(DataRowCollection dataRowCollection)
{
    List<datarow> procedeedRows = new List<datarow><datarow>();
    foreach (DataRow dr in dataRowCollection)
    {
        bool isempty = dr.ItemArray.All(x => x == null || (x!= null && string.IsNullOrWhiteSpace(x.ToString())));

        if (!isempty)
        {
          procedeedRows.Add(dr);
        }
     }
     return procedeedRows;}

static void Main(string[] args)
{
   //code as above function to create datatable 
   List<datarow> drs= GetRowToProcess(table.Rows);
   foreach (DataRow dr in drs)
   {
     //code to process the rows 
   } 
}
</datarow>

Now Difference Between Two Code

In Code (Code Without Yield Keyword)

In this code there is an extra list which gets created that points to the rows that match the condition. Then there is a loop for processing each row.

Disadvantage within this code is an extra list which gets created and occupies the extra space (i.e. occupies memory as well as slows down the code).

In Code (Code With Yield Keyword)

In this no extra list is getting created, with help yield one row at a time with a matching condition is getting processed. The advantage of the code is that there is no extra list getting created and also it also doesn't cause any performance problems.

The following is an example of LINQ with the yield keyword

void Main()
{
   // This uses a custom 'Pair' extension method, defined below.
   List<string> list1 = new List<string>()
 {
     "Pranay",
     "Rana",
     "Hemang",
     "Vyas"
 };
   IEnumerable<string><string>  query = list1.Select (c => c.ToUpper())
  .Pair()         // Local from this point on.
  .OrderBy (n => n.length);
}

public static class MyExtensions
{
 public static IEnumerable<string> Pair (this IEnumerable<string> source)
 {
  string firstHalf = null;
  foreach (string element in source)
  if (firstHalf == null)
   firstHalf = element;
  else
  {
   yield return firstHalf + ", " + element;
   firstHalf = null;
  }
 }
}
</string>

There is other statement besides yeild return

yield break stops returning sequence elements (this happens automatically if the control reaches the end of the iterator method body). The iterator code uses the yield return statement to return each element in turn. yield break ends the iteration.

Constraint

The yield statement can only appear inside an iterator block, which might be used as a body of a method, operator, or accessor. The body of such methods, operators, or accessors is controlled by the following restrictions:

  • Unsafe blocks are not allowed.
  • Parameters to the method, operator, or accessor cannot be ref or out.
  • A yield statement cannot appear in an anonymous method.
  • When used with expression, a yield return statement cannot appear in a catch block or in a try block that has one or more catch clauses.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here