tags:

views:

3031

answers:

10

In the How Can I Expose Only a Fragment of IList<> question one of the answers had the following code snippet:

IEnumerable<object> FilteredList()
{
    foreach( object item in FullList )
    {
        if( IsItemInPartialList( item )
            yield return item;
    }
}

What does the yield keyword do there? I've seen it referenced in a couple places, and one other question, but I haven't quite figured out what it actually does. I'm used to thinking of yield in the sense of one thread yielding to another, but that doesn't seem relevant here.

+5  A: 

Iteration. It creates a state machine "under the covers" that remembers where you were on each additional call to the function and picks up from there.

Joel Coehoorn
A: 

It is a very simple and easy way to create an enumerable for your object. The compiler creates a class that wraps your method and that implements, in this case, IEnumerable<object>. Without the yield keyword, you'd have to create an object that implements IEnumerable<object>.

Will
A: 

It's producing enumerable sequence. What it does is actually creating local IEnumerable sequence and returning it as a method result

aku
+2  A: 

Intuitively, the keyword returns a value from the function without leaving it, i.e. in your code example it returns the current item value and then resumes the loop. More formally, it is used by the compiler to generate code for an iterator. Iterators are functions that return IEnumerable objects. The MSDN has several articles about them.

Konrad Rudolph
+1  A: 

Here is a very good technical explanation:

http://blogs.msdn.com/oldnewthing/archive/2008/08/12/8849519.aspx

Nir
+28  A: 

The yield keyword actually does quite a lot here. The function returns an object that implements the IEnumerable interface. If a calling function starts foreach-ing over this object the function is called again until it "yields". This is syntactic suger introduced in C# 2.0. In earlier versions you had to create your own IEnumerable and IEnumerator objects to do stuff like this.

The easiest way understand code like this is to type in an example, set some breakpoints and see what happens.

Try stepping through this for example:

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}
Mendelt
why not have Integers just be a list?
ooo
In this case that would be easier, i'm just using the integer here to show how yield return works. The nice things about using yield return is that it's a very quick way of implementing the iterator pattern, so things are evaluated lazly.
Mendelt
This makes a lot more sense than anything else I've read on the subject.
Spencer Ruport
+17  A: 

Recently Raymond Chen also ran an interesting series of articles on the yield keyword.

While it's nominally used for easily implementing an iterator pattern, but can be generalized into a state machine. No point in quoting Raymond, the last part also links to other uses (but the example in Entin's blog is esp good, showing how to write async safe code).

Svend
+1  A: 

It's trying to bring in some Ruby Goodness :)
Concept: This is some sample Ruby Code that prints out each element of the array

 rubyArray = [1,2,3,4,5,6,7,8,9,10]
    rubyArray.each{|x| 
        puts x   # do whatever with x
    }

The Array's each method implementation yields control over to the caller (the 'puts x') with each element of the array neatly presented as x. The caller can then do whatever it needs to do with x.

However .Net doesn't go all the way here.. C# seems to have coupled yield with IEnumerable, in a way forcing you to write a foreach loop in the caller as seen in Mendelt's response. Little less elegant.

//calling code
foreach(int i in obCustomClass.Each())
{
    Console.WriteLine(i.ToString());
}

// CustomClass implementation
private int[] data = {1,2,3,4,5,6,7,8,9,10};
public IEnumerable<int> Each()
{
   for(int iLooper=0; iLooper<data.Length; ++iLooper)
        yield return data[iLooper]; 
}
Gishu
A: 

Once you have a good grasp of how iterator blocks work, Eric Lippert has an excellent series of blog posts on some of the seemingly odd restrictions on the generality of iterator blocks.

Grant Wagner