Logo

quadroid

Home
RĂ©sume
Tech Blog

yield to infinity and beyond

There is an awesome keyword in combination with IEnumerable/ IEnumerable<T> returning methods in C# that is not used as widely as I did expect. I am talking about yield.

The yield keyword does allow to creates a enumerator for any method that returns IEnumerable, with little effort.

If I use Primes a lot it is useful to have a method that generates Primes. Now I can create a method that generates the next prime every time I call a method (like the implementation of the Random Class generates one Random number ever Next call). Or I can create a Method GetPrimes that does return a IEmumerable<long> of all primes (until long.MaxValue of course).

I can do this by implementing the PrimesEnumerable by myself, or use yield.
The yield implementation is pretty straight forward:

public IEnumerable<long> GetPrimes()
{
  yield return 2;

  long currentNumber = 3;
  while(true)
  {
    if(IsPrime(currentNumber))
      yield return currentNumber;
    
    currentNumber+=2;
  }
}

As you can see there is no need to define a range/break condition for my infinite method as the compiler does generate a IEnumerable implementation that is not an infinite loop. Usage is as simple as creation.

public void Main()
{
  var somePrimes = this.GetPrimes()
   .Skip(5000)
   .Take(200)
   .ToArray(); // Can be used with Linq
   
  foreach(var prime in this.GetPrimes())
  {
    //process as many primes as I want!
  }

  //this, of course, ends up in chaos 
  var allPrimesAsArray = this.GetPrimes()
   .ToArray();
}

While the last code line ends in an exception, putting all primes into an array is obviously a bad idea in my opinion. yield can be used to return results of finite calculations as well. Just infinite algorithms really shine with the yield keyword. Another great usage is creating a static extension method for the random class to allow simple usage in Linq/foreach like this:

public static class RandomExtensions
{
  public static IEnumerable<int> Randoms(
    this Random target)
  {
    while (true)
      yield return target.Next();
  }
}

If you want to break as there are no more items to return just use yield break; That's it, the next Method returning a bulk of results will be implemented using yield!