2010-09-26 22 views
7

Ho scritto una classe che implementa IEnumerable<T>. Ho un metodo che restituisce MyClass. Se provo a yield return da quel metodo, il compilatore mi dice "... non può essere un blocco iteratore perché ... non è un tipo di interfaccia iteratore".Come definire un tipo di interfaccia iteratore?

Quindi, come posso definire il mio tipo di iteratore dell'interfaccia? Deve essere "astratto" (non è possibile definire alcun metodo)?

Quello che voglio fare è scrivere una serie di metodi concatenabili, quindi ogni metodo dovrebbe restituire un'istanza di MyClass. Ma ho bisogno di MyClass per essere una sorta di enumerabile. Anziché utilizzare un tipo di dati sottostante, speravo di riuscire a trovare solo yield return ovunque.


@Oded:

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

Puoi pubblicare i bit rilevanti del tuo codice? – Oded

risposta

10

No, questo non è possibile. Per capire perché considera di avere una classe Zoo che implementa IEnumerable<Animal> ma ha anche molti altri membri. A Zoo è un IEnumerable<Animal> ma non necessariamente viceversa: una sequenza di animali è solo una sequenza di animali. Non c'è guardiano dello zoo, non ci sono negozi, nessuna quota d'ingresso o nessuna delle altre cose che fanno di uno zoo uno zoo.

Quando si utilizza yield return x il tipo di ritorno non può essere Zoo perché non si dispone di uno zoo - basta una sequenza di animali.

Che cosa si può fare, invece è quella di chiamare come new Zoo(foo()) dove foo restituisce un IEnumerable<Animal> e aggiungere un costruttore per Zoo che accetta un IEnumerable<Animal>.

+0

Anche se 'Zoo' non ha dati, solo metodi? – mpen

+2

Se si dispone solo di metodi, è possibile implementarli come metodi di estensione su "IEnumerable ". Poi penso che ottieni ciò che volevi: puoi facilmente usare la resa e puoi avere metodi specializzati sulle tue sequenze. –

+0

Ho bisogno di un costruttore però ... che produrrebbe solo un elemento immagino. Quindi suppongo che potrei usare una funzione pubblica per quello. Devo pensarci un po 'di più ... se voglio davvero limitarmi a una classe apolide ... comunque è un'idea carina. Grazie! – mpen

2

Penso che quando si utilizza yield return x si produca un IEnumerable di tipo X. Quindi nel tuo caso sarebbe IEnumerable

Ereditare da una classe non significherebbe automaticamente che implicitamente si assegnerà a quel tipo. Quindi se scrivi

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

funziona. IEnumerable non è lo stesso di SharpQuery.

+0

Questo NON funziona perché HtmlNode non è definito. – user1789573

+0

Buona presa. Sì, in realtà è una versione ridotta. SharpQuery non implementa effettivamente IEnumerable, ma il ritorno di Trova funzionerà. L'ho riparato. – abhishek

2

Secondo la sezione 8.2 del linguaggio C# Specification Version 4.0:

Un blocco che contiene uno o più yield dichiarazioni viene chiamato un blocco iteratore. I blocchi iteratori vengono utilizzati per implementare i membri della funzione come iteratori.

Sezione 10.14 specifica che il tipo di ritorno di un iteratore deve essere uno dei seguenti:

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

Secondo la sezione 10.14.4, richiamando un iteratore non esegue immediatamente il codice nel blocco iteratore. Invece, un oggetto enumeratore che implementa le seguenti interfacce viene creato e restituito:

  • IEnumerator
  • IEnumerator<T>
  • IDisposable

L'oggetto enumeratore è solitamente un'istanza di una classe nidificata generato dal compilatore con accessibilità privata.

+0

Penso di voler restituire qualcosa che ha implementato una di queste interfacce, piuttosto che l'interfaccia stessa. – mpen

+0

Per https://msdn.microsoft.com/en-us/library/ms228593.aspx la specifica C# viene installata con Visual Studio in 'Programmi (x86)/Microsoft Visual Studio 12.0/VC#/Specifiche/1033'. Cambia la versione di Visual Studio come appropriato, 14.0 per VS2015, ecc – BurnsBA

Problemi correlati