Some help understanding "yield"

In my everlasting quest to suck less I'm trying to understand the "yield" statement, but I keep encountering the same error.

The body of [someMethod] cannot be an iterator block because 'System.Collections.Generic.List< AClass>' is not an iterator interface type.

This is the code where I got stuck:

foreach (XElement header in headersXml.Root.Elements()){
    yield return (ParseHeader(header));                
}

What am I doing wrong? Can't I use yield in an iterator? Then what's the point? In this example it said that List<ProductMixHeader> is not an iterator interface type. ProductMixHeader is a custom class, but I imagine List is an iterator interface type, no?

--Edit--
Thanks for all the quick answers.
I know this question isn't all that new and the same resources keep popping up.
It turned out I was thinking I could return List<AClass> as a return type, but since List<T> isn't lazy, it cannot. Changing my return type to IEnumerable<T> solved the problem :D

A somewhat related question (not worth opening a new thread): is it worth giving IEnumerable<T> as a return type if I'm sure that 99% of the cases I'm going to go .ToList() anyway? What will the performance implications be?


A method using yield return must be declared as returning one of the following two interfaces:

IEnumerable<SomethingAppropriate>
IEnumerator<SomethingApropriate>

(thanks Jon and Marc for pointing out IEnumerator)

Example:

public IEnumerable<AClass> YourMethod()
{
    foreach (XElement header in headersXml.Root.Elements())
    {
        yield return (ParseHeader(header));                
    }
}

yield is a lazy producer of data, only producing another item after the first has been retrieved, whereas returning a list will return everything in one go.

So there is a difference, and you need to declare the method correctly.

For more information, read Jon's answer here, which contains some very useful links.


It's a tricky topic. In a nutshell, it's an easy way of implementing IEnumerable and its friends. The compiler builds you a state machine, transforming parameters and local variables into instance variables in a new class. Complicated stuff.

I have a few resources on this:

  • Chapter 6 of C# in Depth (free download from that page)
  • Iterators, iterator blocks and data pipelines (article)
  • Iterator block implementation details (article)

  • "yield" creates an iterator block - a compiler generated class that can implement either IEnumerable[<T>] or IEnumerator[<T>] . Jon Skeet has a very good (and free) discussion of this in chapter 6 of C# in Depth.

    But basically - to use "yield" your method must return an IEnumerable[<T>] or IEnumerator[<T>] . In this case:

    public IEnumerable<AClass> SomeMethod() {
        // ...
        foreach (XElement header in headersXml.Root.Elements()){
            yield return (ParseHeader(header));                
        }
    }
    
    链接地址: http://www.djcxy.com/p/9110.html

    上一篇: 何时使用Yield?

    下一篇: 有些有助于理解“收益”