Though Yield
return key phase in C# is quite old, it was introduced in C# 2.0. But at that time, I was quite new to C# and indeed was not writing any blogs. C# yield
key phase always fascinates me and I always wanted to write an article about this mighty key phase.
Yield
return key phase is used to maintain the state machine for a particular collection. It maintains a state machine, but how? What CLR does is that wherever it sees yield
return key phase being used, CLR implements an Enumerator pattern to that piece of code. This type of implementation helps the developer from all the type of plumbing which we would have otherwise done in the absence of the keyword. Suppose the developer is filtering some collection, iterating though the collection and then extracting those objects in some new collection. This kind of plumbing is quite monotonous.
As mentioned earlier in my article, yield
is not a keyword, it means that it still can be used as variable. However yield return
and yield break
are key phrases. Everytime the compiler executes yield return
, the generated code will return that value followed by the phase. What happens is that the compiler generated an enumerator that adds the WhileMoveNext
return-current plumbing without losing the memory from stack. It means that as long as there are more and more items, the stack memory for that collection is kept intact. When the last item is hit – MoveNext
returns false
and the stack is unbound and finally
block is executed. The function which uses Yield return
phase returns IEnumerable<T>
type. It means that there is no need to write the same logic for different types which again prevents from type safe plumbing.
Here in this article, I want to show you how I have used the yield return
phase to get the list of all the prime numbers between some range of integers while still keeping my application responsive. If I would not have used the yield return
phase in that case, I could have used a new collection in the method and waited for that method to complete its operation and return the whole collection of prime numbers at one go. Though whatever code I have written here is to display the capability of the yield return
phase. I am sure this functionality can be achieved in a much better way.
In my demo project, I have used a function as shown below which uses the yield
keyword phase.
static IEnumerable<int> GetPrimes(int from, int to)
{
for (int i = from; i <= to; i++)
{
if (!_worker.CancellationPending)
{
bool isPrime = true;
int limit = (int)Math.Sqrt(i);
for (int j = 2; j <= limit; j++)
if (i % j == 0)
{
isPrime = false;
break;
}
if (isPrime)
{
yield return i;
}
}
}
}
In the above code snippet, we can see that as soon as the execution finds a prime number, the function returns that prime number, remembering the state of the collection from which it returned. While the collection keeps returning values, the ListBox
keeps updating itself with the values received from the collection, which helps us not to wait for whole result in one go. Try giving a bigger range like 1 to 10000 and you will be able to see the desired result.
Listed below are some of the basic rules which we should keep in mind while using yield return
:
Yield return
should only return the expression whose type should be the type of iterator
Yield return
should be inside an iterator block and the iterator block can be in a method body, operator function or property.
Yield
statement cannot appear in anonymous methods.
Kindly share your thought about the article.