2012-07-03 10 views
11

Esta es probablemente una pregunta de sintaxis simple, pero no puedo resolverlo.Implementando IEnumerable con una matriz

Normalmente, me gustaría hacer esto:

public class OrderBook : IEnumerable<PriceLevel> 
{ 
    private readonly List<PriceLevel> PriceLevels = new List<PriceLevel>(); 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 

Pero en lugar de una lista, quiero utilizar una matriz - como esto:

public class ArrayOrderBook : IEnumerable<PriceLevel> 
{ 
    private PriceLevel[] PriceLevels = new PriceLevel[500]; 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 

El IEnumerator IEnumerable.GetEnumerator() parece compilarse bien - pero el public IEnumerator<PriceLevel> dice que necesito algún tipo de yeso: ¿cuál es la mejor manera de hacerlo?

William

+2

¿Por qué? ¿Por qué usar una matriz para esto? – Oded

+1

'List' está respaldado por una matriz, por lo que no está obteniendo nada, excepto una complicación excesiva de su trabajo. – Tudor

+1

@Tudor, dependiendo de qué otra lógica vaya en la clase, podría tener más sentido que 'PriceLevels' sea una matriz (por ejemplo, un tamaño fijo). No hay nada de malo en querer refactorizar eso. –

Respuesta

14

Prueba esto:

public class ArrayOrderBook : IEnumerable<PriceLevel> 
{ 
    private PriceLevel[] PriceLevels = new PriceLevel[500]; 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.AsEnumerable().GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 
+1

Se puede inferir el tipo. '.AsEnumerable()' funciona bien. 'T []' implementa 'IEnumerable ', pero su método público para 'GetEnumerator' devuelve' IEnumerator' de tipo débil. –

+0

@TimS. ¡Estás absolutamente en lo correcto! –

6

Como se puede ver en su propio IEnumerable<T> aplicación, es necesario proporcionar tanto una versión genérica y no genérico del método para cumplir con la interfaz. Para hacer esto, dado que los métodos tienen la misma firma, uno de ellos debe ser una implementación de interfaz explícita. En el caso de List, la versión genérica es un método en la clase y la versión no genérica es una definición de interfaz explícita, ya que la versión genérica es generalmente más útil. En el caso de una matriz, ya tenía la versión no genérica como implementación y estaba agregando la versión genérica del método en una versión posterior. Para evitar el cambio de rotura, la versión genérica es la definición de interfaz explícita en su lugar.

Existen varias maneras de solucionar este problema. Aquí hay tres simples.

public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    return PriceLevels.AsEnumerable().GetEnumerator(); 
} 


public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    IEnumerable<PriceLevel> enumerator = PriceLevels; 
    return enumerator.GetEnumerator(); 
} 

public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator() 
} 
+0

+1 para la respuesta más completa. – phoog

4

moldeada T[] a la correspondiente IEnumerable<T>:

public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator(); 
    } 
2

Según ECMA-335 de partición I, §8.9.1, un tipo de vector (array sola dimensión como T[]) implementa IList<T> que implica que también implementa IEnumerable<T>. Sin embargo, la implementación de los métodos es explícita, por lo que necesitaría usar uno de estos:

Opción 1: Simplemente use la asignación implícita de matrices en IList<T>.

private IList<PriceLevel> PriceLevels = new PriceLevel[500]; 

Opción 2: Dejar la variable miembro como una matriz, y utilizar el método AsEnumerable extensión. Este método de extensión usa una asignación implícita soportada que es preferible a usar un lanzamiento directo como (IEnumerable<PriceLevel>)PriceLevels.

IEnumerator IEnumerable.GetEnumerator() 
{ 
    return PriceLevels.AsEnumerable().GetEnumerator(); 
} 

artículos que deben evitarse:

  1. El método Cast<T> introduce un cheque tipo innecesario para cada elemento de la matriz y se debe evitar.
  2. Si solo necesita incluir elementos no nulos de la enumeración, puede utilizar el método de extensión OfType<T>. De lo contrario, este método también introduce una verificación de tipo innecesaria en cada elemento.
Cuestiones relacionadas