Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define an iterator interface type?

Tags:

c#

I've written a class that implements IEnumerable<T>. I have a method that returns MyClass. If I try to yield return from within that method, the compiler tells me "... cannot be an iterator block because ... is not an iterator interface type".

So, how can I define my own interface iterator type? Does it have to be "abstract" (can't have any methods defined)?

What I want to do is write a bunch of chainable methods, so every method should return an instance of MyClass. But I need MyClass to be some kind of enumerable. Rather than using some underlying data type, I was hoping I could just yield return everywhere.


@Oded:

class SharpQuery : IEnumerable<HtmlNode>
{
    public SharpQuery Find(string selector)
    {
        foreach (var n in this)
        {
            // filter the results
            yield return node;
        }
    }
}
like image 945
mpen Avatar asked Sep 26 '10 19:09

mpen


3 Answers

I think when you use yield return x you will be producing an IEnumerable of X type. So in your case it would be IEnumerable

Inheriting from one class would not automatically mean it will implicitly cast itself to that type. So if you write

class SharpQuery 
{
    public IEnumerable<HtmlNode> RepositoryItems { get; set; }
    public IEnumerable<HtmlNode> Find(string selector)
    {
        foreach (var n in this.RepositoryItems)
        {
            // filter the results
            yield return node;
        }
    }
}

it works. IEnumerable is not same as SharpQuery.

like image 72
abhishek Avatar answered Oct 13 '22 02:10

abhishek


No, that's not possible. To see why consider that you have a class Zoo that implements IEnumerable<Animal> but also has lots of other members. A Zoois an IEnumerable<Animal> but not necessarily vice versa - a sequence of animals is just a sequence of animals. There's no zoo keeper, no shops, no entrance fee or any of the other things that makes a zoo a zoo.

When you use yield return x the return type cannot be Zoo because you don't have a zoo - you just have a sequence of animals.

What you can do instead is to call it as new Zoo(foo()) where foo returns an IEnumerable<Animal> and add a constructor to Zoo that accepts an IEnumerable<Animal>.

like image 38
Mark Byers Avatar answered Oct 13 '22 04:10

Mark Byers


According to section 8.2 of the C# Language Specification Version 4.0:

A block that contains one or more yield statements is called an iterator block. Iterator blocks are used to implement function members as iterators.

Section 10.14 specifies that the return type of an iterator must be one of the following:

  • IEnumerator
  • IEnumerable
  • IEnumerator<T>
  • IEnumerable<T>

According to section 10.14.4, invoking an iterator does not immediately execute the code in the iterator block. Instead, an enumerator object that implements the following interfaces is created and returned:

  • IEnumerator
  • IEnumerator<T>
  • IDisposable

The enumerator object is typically an instance of a compiler-generated nested class with private accessibility.

like image 21
Ryan Prechel Avatar answered Oct 13 '22 02:10

Ryan Prechel