Vasu Balakrishnan’s Blog

C# Yield Keyword

leave a comment »

According to MSDN “Used in an iterator block to provide value to the enumerator object or to signal the end of iteration”. But there is much more to this keyword, which I found is not explained well (at least to me) in the documentation. You’ll see that yield keyword is sort of foundation to LINQ concepts and introduces the notion of lazy evaluation (which people familiar with Functional Programming know).

Yield allows one enumerable function to be implemented in terms of another. It avoids lot of code that we had to write in order to expose a custom enumerator. This was introduced in C# 2.0 and back then I was able to write the code below

public class MyCollection<T>
{
    private List<T> Items;

    ...

    public IEnumerable<T> FindAll(Predicate<T> pPredicate)
    {
        foreach (T lItem in Items)
        {
            if (pPredicate.Invoke(lItem))
                yield return lItem;
        }
    }
}

I didn’t pay attention to this until I started to use LINQ / Functional Programming concepts. The reason is yield return exhibits a lazy evaluation / deferred execution behaviors. I didn’t get it at first. For this I had to understand the behavior of the IEnumerator.

Enumerators are used to read data in a collection. Initially, the enumerator is positioned before the first element. You must call MoveNext to advance the enumerator and retrieve the value using Current property. MoveNext tells you whether you’ve hit the end of collection by returning false.

When you use yield keyword, the compiler internally creates an Enumerator class that keeps the state of current iteration. When you are iterating a collection that is implemented using yield return, you’re moving from item to item in the Enumerator using MovingNext method. That’s the key right here for the lazy evaluation.

When the code encounters a yield return statement, it gets the item from the enumerator and returns it to the caller. Any other code following the yield statement is not executed and the next item is not processed, until the caller requests for the next item. This is where lazy evaluation comes into picture. You don’t have to enumerate all the items in the collection, and you do so only if the caller asks for it.  Also, when a method has a yield statement, the execution of method doesn’t begin until the calling method first iterates over the resulting IEnumerable. This is known as Deferred Execution. With these, you can chain iterators without actually enumerating anything until you actually need them.

This is the foundation block for LINQ. LINQ Operators like Select, Where, etc are implemented as iterators that are created with yield statement.

For further reading, I would recommend these articles

Advertisements

Written by nbvasu

May 20, 2009 at 3:35 pm

Posted in C#

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: