tags:

views:

273

answers:

4

Possible Duplicate:
C# - Proper Use of yield return

What can be a real use case for C# yield?

Thanks.

+7  A: 

When you want deferred execution.

This makes sense in most cases where the alternative is to construct a temporary collection.

Consider this scenario: I have a list of integers and I want to list their squares.

I could do this:

public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
    List<int> squares = new List<int>();
    foreach (int number in numbers)
        squares.Add(number * number);

    return squares;
}

Then I could sum the squares, take their average, find the greatest, etc.

But I really didn't need to populate a whole new List<int> for that purpose. I could've used yield to enumerate over the initial list and return the squares one-by-one:

public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
    foreach (int number in numbers)
        yield return number * number;
}

The fact that this actually makes a difference might not be apparent until you start dealing with very large collections, where populating temporary collections proves to be quite wasteful.

For example suppose I wanted to find the first square above a certain threshold. I could do this:

IEnumerable<int> numbers = GetLotsOfNumbers();
var squares = numbers.Squares();
int firstBigSquare = squares
    .Where(x => x >= 1000)
    .FirstOrDefault();

But if my Squares method populated an entire List<int> before returning, the above code would be doing potentially far more work than necessary.

Dan Tao
Well written example. + 1 for why the difference might not be apparent.
Paddy
+7  A: 

From the MSDN page on yield:

Used in an iterator block to provide a value to the enumerator object or to signal the end of iteration.

You use it when creating a custom iterator. Using the example from the page:

// yield-example.cs
using System;
using System.Collections;
public class List
{
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}

The yield means that the while loop inside Power effectively "pauses" after each iteration to allow the calling routine to perform some action. In this case printing out the result.

ChrisF
+7  A: 

When you're too lazy to write your own IEnumerator ;)

Rex M
+1 I think I'm always too lazy...
Adam Driscoll
And it should probably be noted that there's a difference between IEnumerator and IEnumerable the words are spelled similarly enough that I used to be confused because I was reading different definitions for what I thought was the same thing
Davy8
@Davy8 very true! Many people are confused by the difference. The IEnumerator contains all the logic hidden behind yield; the IEnumerable would just provide access to the IEnumerator.
Rex M
Can IEnumerator replace yield functionality?
NewB
@NewB writing your own IEnumerable and IEnumerator classes is the "manual" way to create your own complex enumeration logic, like deferred execution, projections, filtering, etc. The compiler just gives us a quick "shortcut" by using yield. It is not as powerful, but just a keyword instead of a whole class so for simple cases it is faster and easier.
Rex M
Do you mean that yiels is a compiler implementation of IEnumer* interfaces behind the scenes? Or that both of them are translated in the same way by the compiler?Besides, see Dan Tao's answer below - it uses yield in addition to IEnumerable.
NewB
@NewB and that's what I mean by the confusion between IEnumerator and IEnumerable. An IEnumerable is what people usually work with, it is an order collection of value that can potentially be infinite in length using an IEnumerator. The IEnumerATOR is what tells a foreach look how to get the next value in the specified IEnumerABLE
Davy8
@NewB Dan Tao's answer is returning an IEnumerable, he did not write his own IEnumerable class. That's the difference - you could return an IEnumerable with yield, or write your own IEnumerable class and return that.
Rex M
Thank you all!!
NewB
+1  A: 

See this article.

Yield acts as a return-placeholder - it's a non-local goto return point which preserves the method's environment and allows the code to "jump" back in. In a way similar (kind of inverted) to passing a delegate into a method which allows you to inject specific logic within another method, closures allow you to do different types of work "around" a more general method, allowing you to keep code small and modular and re-usable.

This could make for much more efficient code. Instead of instantiating a very large collection, it might be possible to allow individual objects to be acted upon in sequence(and they are discarded after each operation). I imagine you could construct cases where a straightforward iterator would be extremely difficult to build.

Cade Roux