DEV Community

Ahmed Fouad
Ahmed Fouad

Posted on • Originally published at Medium on

Generator Pattern using CSharp and Linq

Reactive Programming

The Generator Pattern or the unbound list is a very old technique in functional programming (Haskell) that is possible due to the lazy execution technique.

IEnumerable<int> EvenNumbers=EnumerableEx.From(x=>2x);
Console.Writeline(EvenNumbers[2]);//4

The previous example demonstrated how the generator pattern could be used in CSharp.

When we defined our EvenNumbers=EnumerableEx.From(x=>2x), we only defined a strategy for calculation any element in the enumerable but the function will only get executed when you access one of it is elements.

List<int> EvenNumbers=EnumerableEx.From(x=>2x).Take(10).ToList();
Console.Writeline(EvenNumbers); //0,2,4,3,8,10,12,14,16,18

The conversation between the Inbounded list and the bounded list is simply achieved by adding bounds using linq Skip and Take operators.

Execution Control

In normal c# imperative code, the execution control is usually done by loops and conditions (the natural evolution of GoTo). The factory pattern unleashes the power of LINQ for execution control.

Parallel programming(PLINQ)

var evenNumbers=EnumerableEx.From(x=>2x).Take(10).AsParallel().ToList();
Console.Writeline(EvenNumbers);

Conditions for skipping and Taking

var evenNumbers=EnumerableEx.From(x=>2x);

var data = evenNumbers.Scan((0, 0), (tuple, i) => (i, tuple.Item2 + i))
.Skip(1)
.TakeWhile(i => i.Item2 <= 12)
.Select(tuple => tuple.Item1).ToList();

The previous method will return all the even numbers that their sum is less than or equal to 12 {0,2,4,6}.

you can find the scan method and more linq extensions in the LinqMore Library

https://morelinq.github.io/

Memorization

When dealing with lazy execution memorization is a very important concept as it prevents the recalculation of enumerable elements.

var evenNumbers=EnumerableEx.From(x=>2x);
var data1 =evenNumbers.Take(10).ToList();
var data2 =evenNumbers.Take(20).ToList();

the previous code problem is that it will calculate the first 10 elements in order to build the data1 list and then it will calculate the first 20 elements independently in order to build the data2 list. that means that the first 10 elements are calculated twice.

In order to resolve this, I will use the .Memorize() extension method from the LinqMore library.

var evenNumbers=EnumerableEx.From(x=>2x).Memorize();
var data1 =evenNumbers.Take(10).ToList();
var data2 =evenNumbers.Take(20).ToList();

Now the first 10 elements will get calculated and memorized when building the data1 list and they will get recalled when building the data2 so the elements from 10 to 20 will only get calculated.

Generator Pattern Implementation

Our implementation starts with the Generator Enmurable Which implements the IEnumerable Interface

it is very straight forward it receives the generator function as a parameter and every time the MoveNext method is called it generates the item using the generator function and increments the index.

and here the standard implementation of the IEnumerable

and finally the EnumerableEx helper class

public static class EnumerableEx

{

public static IEnumerable<T> From<T>( Func<int, T> generatorFunc)

{

return new Generator<T>(generatorFunc);

}

}

A Real-Life example

Personally I have used the generator pattern in a lot of projects that I cannot reveal here so it is kind of hard to give you a high-quality real-life example but I can ask you to build a xamarin mobile app that shows the user 2 numbers on the screen and ask him to sum it, if he do it correctly add one point to his score and if the wrong deducts one point. He wins only when his score is 10 and he loose when his score is -10.

if you like this article please share it on your social media and I appreciate if you would like to pay the coffee for me on

Buy AhmedFouad a Coffee. ko-fi.com/ahmedfouad

Top comments (0)