2010-09-26 15 views
7

Ich habe eine Klasse geschrieben, die IEnumerable<T> implementiert. Ich habe eine Methode, die MyClass zurückgibt. Wenn ich versuche, innerhalb dieser Methode yield return, der Compiler sagt mir "... kann nicht ein Iterator-Block sein, weil ... ist kein Iterator-Interface-Typ".Wie definiere ich einen Iterator-Interface-Typ?

Also, wie kann ich meinen eigenen Interface-Iterator-Typ definieren? Muss es "abstrakt" sein (können keine Methoden definiert sein)?

Was ich tun möchte, ist eine Reihe von chainable Methoden schreiben, so sollte jede Methode eine Instanz von MyClass zurückgeben. Aber ich brauche MyClass um eine Art aufzählbar zu sein. Anstatt einen zugrunde liegenden Datentyp zu verwenden, habe ich gehofft, ich könnte einfach überall hin.


@Oded:

class SharpQuery : IEnumerable<HtmlNode> 
{ 
    public SharpQuery Find(string selector) 
    { 
     foreach (var n in this) 
     { 
      // filter the results 
      yield return node; 
     } 
    } 
} 
+1

Können Sie die relevanten Bits Ihres Codes veröffentlichen? – Oded

Antwort

10

Nein, das ist nicht möglich. Um zu sehen, warum Sie denken, dass Sie eine Klasse Zoo haben, die IEnumerable<Animal> implementiert, hat aber auch viele andere Mitglieder. Eine Zoo ist eine IEnumerable<Animal>, aber nicht unbedingt umgekehrt - eine Sequenz von Tieren ist nur eine Sequenz von Tieren. Es gibt keinen Tierpfleger, keine Geschäfte, keinen Eintritt oder andere Dinge, die einen Zoo zu einem Zoo machen.

Wenn Sie yield return x verwenden, kann der Rückgabetyp nicht Zoo sein, weil Sie keinen Zoo haben - Sie haben nur eine Folge von Tieren.

Was können Sie stattdessen tun, ist es als new Zoo(foo()) zu nennen, wo foo eine IEnumerable<Animal> zurückgibt und einen Konstruktor Zoo hinzufügen, die ein IEnumerable<Animal> akzeptiert.

+0

Auch wenn 'Zoo' keine Daten hat, nur Methoden? – mpen

+2

Wenn Sie nur Methoden haben, können Sie diese als Erweiterungsmethoden für IEnumerable implementieren. Dann denke ich, dass Sie bekommen, was Sie wollten - Sie können einfach Ertrag verwenden, und Sie können spezialisierte Methoden auf Ihre Sequenzen haben. –

+0

Ich brauche einen Konstruktor obwohl ... was nur einen Gegenstand ergeben würde, denke ich. Dann könnte ich stattdessen einfach eine öffentliche Funktion verwenden. Ich muss darüber noch etwas nachdenken ... wenn ich mich wirklich auf eine staatenlose Klasse beschränken will ... es ist eine nette Idee. Vielen Dank! – mpen

2

Ich denke, wenn Sie yield return x verwenden, werden Sie eine IEnumerable des X-Typs produzieren. In Ihrem Fall wäre es also IEnumerable

Vererbung von einer Klasse würde nicht automatisch bedeuten, dass es sich implizit auf diesen Typ wirft. Also, wenn Sie schreiben

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; 
     } 
    } 
} 

es funktioniert. IEnumerable ist nicht dasselbe wie SharpQuery.

+0

Dies funktioniert NICHT, da HtmlNode nicht definiert ist. – user1789573

+0

Guter Fang. Ja, eigentlich ist es eine abgespeckte Version. SharpQuery implementiert IEnumerable nicht tatsächlich, aber die Rückgabe von Find funktioniert. Ich habe es behoben. – abhishek

2

Gemäß Abschnitt 8.2 der C# Language Specification Version 4.0:

Ein Block, der eine oder mehr yield Aussagen enthält, wird einen Iteratorblock genannt. Iteratorblöcke werden verwendet, um Funktionsmember als Iteratoren zu implementieren.

Abschnitt 10.14 gibt an, dass der Rückgabetyp eines Iterators eine der folgenden sein:

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

Gemäß Abschnitt 10.14.In 4 führt das Aufrufen eines Iterators nicht sofort den Code im Iteratorblock aus. Stattdessen wird ein Enumerator Objekt, das die folgenden Schnittstellen implementiert wird erzeugt und zurückgegeben:

  • IEnumerator
  • IEnumerator<T>
  • IDisposable

Die Enumeratorobjekt ist typischerweise eine Instanz eines Compiler generierte geschachtelte Klasse mit privater zugänglichkeit.

+0

Ich glaube, ich wollte etwas zurückgeben, das eine dieser Schnittstellen implementiert hat, und nicht die Schnittstelle selbst. – mpen

+0

Per https://msdn.microsoft.com/en-us/library/ms228593.aspx wird die C# -Spezifikation mit Visual Studio unter 'Programme (x86)/Microsoft Visual Studio 12.0/VC#/Spezifikationen/1033' installiert. Ändern Sie die Visual Studio - Version entsprechend, 14,0 für VS2015 usw – BurnsBA

Verwandte Themen