2010-09-26 11 views
7

Escribí una clase que implementa IEnumerable<T>. Tengo un método que devuelve MyClass. Si trato de yield return desde ese método, el compilador me dice "... no puede ser un bloque iterador porque ... no es un tipo de interfaz de iterador".¿Cómo se define un tipo de interfaz de iterador?

Entonces, ¿cómo puedo definir mi propio tipo de iterador de interfaz? ¿Tiene que ser "abstracto" (no puede haber ningún método definido)?

Lo que quiero hacer es escribir un montón de métodos encadenables, por lo que cada método debe devolver una instancia de MyClass. Pero necesito MyClass para ser un tipo de enumerable. En lugar de utilizar algún tipo de datos subyacente, esperaba poder simplemente yield return en todas partes.


@Oded:

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

¿Puedes publicar los bits relevantes de tu código? – Oded

Respuesta

10

No, eso no es posible. Para ver por qué, considere que tiene una clase Zoo que implementa IEnumerable<Animal> pero también tiene muchos otros miembros. Un Zoo es un IEnumerable<Animal> pero no necesariamente viceversa: una secuencia de animales es solo una secuencia de animales. No hay guardián del zoológico, ni tiendas, ni entrada, ni ninguna de las otras cosas que hacen que un zoológico sea un zoológico.

Cuando usa yield return x, el tipo de devolución no puede ser Zoo porque no tiene un zoológico; solo tiene una secuencia de animales.

Lo que puede hacer en su lugar es llamar como new Zoo(foo()) donde foo devuelve un IEnumerable<Animal> y añadir un constructor para Zoo que acepta un IEnumerable<Animal>.

+0

Incluso si 'Zoo' no tiene datos, ¿solo métodos? – mpen

+2

Si solo tiene métodos, puede implementarlos como métodos de extensión en 'IEnumerable '. Entonces creo que obtienes lo que querías, puedes usar el rendimiento fácilmente y puedes tener métodos especializados en tus secuencias. –

+0

Sin embargo, necesito un constructor ... que arrojaría solo un elemento, supongo. Entonces creo que podría usar una función pública para eso. Tengo que pensar en esto un poco más ... si realmente quiero restringirme a una clase sin estado ... es una buena idea sin embargo. ¡Gracias! – mpen

2

Creo que cuando use yield return x producirá un IEnumerable de tipo X. Por lo tanto, en su caso sería IEnumerable

Heredar de una clase no significa automáticamente que se lanzará implícitamente a ese tipo. Por lo tanto, si escribe

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

funciona. IEnumerable no es lo mismo que SharpQuery.

+0

Esto NO funciona porque HtmlNode no está definido. – user1789573

+0

Buena captura. Sí, en realidad es una versión despojada. SharpQuery no implementa IEnumerable en realidad, pero el retorno de Find funcionará. Lo he arreglado. – abhishek

2

Según la sección 8.2 de la C# Language Specification Version 4.0:

un bloque que contiene uno o más yield declaraciones se llama un bloque de iterador. Los bloques Iterator se usan para implementar miembros de funciones como iteradores.

Sección 10.14 especifica que el tipo de retorno de un iterador debe ser uno de los siguientes:

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

De acuerdo con la sección 10.14.4, al invocar un iterador no se ejecuta inmediatamente el código en el bloque iterador. En lugar de ello, un objeto empadronador que implementa las siguientes interfaces se crea y se volvió:

  • IEnumerator
  • IEnumerator<T>
  • IDisposable

El objeto empadronador es típicamente una instancia de una clase anidada generado por el compilador con accesibilidad privada.

+0

Creo que quería devolver algo que implementara una de esas interfaces, en lugar de la interfaz en sí. – mpen

+0

Por https://msdn.microsoft.com/en-us/library/ms228593.aspx la especificación de C# se instala con Visual Studio en 'Archivos de programa (x86)/Microsoft Visual Studio 12.0/VC#/Specifications/1033'. Cambiar la versión de Visual Studio según corresponda, 14.0 para VS2015, etc. – BurnsBA

Cuestiones relacionadas