Use-of-Yield-Keyword-in-C-sharp

Use of Yield in C#

Use of Yield in C#

Quote from MSDN

“The yield keyword signals to the compiler that the method in which it appears is an iterator block. The compiler generates a class to implement the behavior that is expressed in the iterator block. In the iterator block, the yield keyword is used together with the return keyword to provide a value to the enumerator object. This is the value that is returned, for example, in each loop of a foreach statement. The yield keyword is also used with break to signal the end of iteration.”

Basically in two different scenarios yield could be used:

  1. Conditional iteration through a collection.
  2. Stateful iteration.

1. Conditional iteration through a collection using Yield.

To understand why we could use Yield keyword, we will take a simple example of iteration to understand Yield. Let’s understand below example first and then we will use Yield keyword as an alternative of simple conditional iteration.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Enumerate_Enum_csharp
{
    class Program
    {
        static List<int> MyList = new List<int>();
        static void FillValues()
        {
            MyList.Add(1);
            MyList.Add(2);
            MyList.Add(3);
            MyList.Add(4);
            MyList.Add(5);
        }
        static void Main(string[] args)
        {
            FillValues(); 
            foreach (var item in FilterWithoutYield())
            {
                Console.WriteLine(item);
            }
              
            Console.ReadLine();
        }

        static IEnumerable<int> FilterWithoutYield()
        {
            List<int> temp = new List<int>();
            foreach (int i in MyList)
            {
                if (i > 3)
                {
                    temp.Add(i);
                }
            }
            return temp;
        }

    }
}

Here we are trying to get all the numbers which are greater than 3 in list of Integer. We could also achieve same thing by using Yield Keyword as demonstrate below code, as a Yield is containing state (will explain you regarding statefull iteration using Yield in second point) Yield will return first possible value to caller and caller execute its code and then again yield will return value and caller will execute its code and so on….

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Enumerate_Enum_csharp
{
    class Program
    {
        static List<int> MyList = new List<int>();
        static void FillValues()
        {
            MyList.Add(1);
            MyList.Add(2);
            MyList.Add(3);
            MyList.Add(4);
            MyList.Add(5);
        }
        static void Main(string[] args)
        {
            FillValues();
            foreach (var item in FilterWithoutYield())
            {
                Console.WriteLine(item);
            }
            foreach (var item in FilterWithYield())
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }

        private static IEnumerable<int> FilterWithYield()
        {
            foreach (int i in MyList)
            {
                if (i > 3)
                {
                    yield return i;
                }
            }
        }

        static IEnumerable<int> FilterWithoutYield()
        {
            List<int> temp = new List<int>();
            foreach (int i in MyList)
            {
                if (i > 3)
                {
                    temp.Add(i);
                }
            }
            return temp;
        }
 
    }
}

 

2. Stateful iteration.

As I have explained in first point Yield remember the state, we could use Yield keyword in stateful iteration as well. To demonstrate this functionality we will be using running total example to understand in a better way.

static IEnumerable<int> RunningTotal()
{
    int runningtotal = 0;
    foreach (int i in MyList)
    {
        runningtotal += i;
        yield return (runningtotal);
    }
}

//Caller is as below
foreach (int i in RunningTotal())
{
    Console.WriteLine(i);
} 
Console.ReadLine();

Output:

Running Total using Yield
Running Total using Yield

Performance measurement of Yield keyword against normal iteration

What do you thing what should be the measurement result?? Will really Yield keyword use make our code faster or we have to compromise our performance to achieve readability in our code!!!

Let’s rewrite the first point code and try to measure timings by using stopwatch.

FillValues(); // Fills the list with 5 values

var s1 = Stopwatch.StartNew();
foreach (var item in FilterWithoutYield())
{
    Console.WriteLine(item);
}
s1.Stop();
var s2 = Stopwatch.StartNew();
foreach (var item in FilterWithYield())
{
    Console.WriteLine(item);
}
s2.Stop();

Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));

Output:

Performance-Yield-keyword
Performance-Yield-keyword

By using this experiment we could find that normal iteration has taken 1.17 ns and with Yield keyword iteration took 1.74 ns. Which stats that Yield is slower in this scenario. So I urge you to take measurement before choosing Yield keyword as using yield CLR has to create internal class at execution time. Sometime Yield could also reduce timing of execution.

Points to be remembered:

  1. Do not put “yield” in an unsafe block.
  2. Do not use ref or out keywords with the parameters of the method, operator or getter / setter.
  3. “Yield return” can only be placed in the try block if it is followed by a finally block.
  4. “Yield break” can be put in the try block and catch, but not placed in the finally block.
  5. Do not use “yield” of the anonymous method.
  6. Main disadvantage of yield is creation of additional iterator class. When sequence is finite and caller doesn’t have complex logic, yield is slower and allocates more memory. Usage of yield makes sense in cases of data processing when each collection computation causes large memory block allocation. Lazy nature of yield can help to avoid computation of elements that will be filtered. In such cases, yield significantly reduces memory consumption and CPU load.

You can download whole code of Use of Yield in C# from here.

Leave a Reply