2012-07-03 17 views
11

Questa è probabilmente una semplice domanda di sintassi, ma non riesco a capirlo.Implementazione di IEnumerable con una matrice

Normalmente, vorrei fare questo:

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

Ma invece di una lista, voglio utilizzare un array - simile a questo:

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

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

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

La IEnumerator IEnumerable.GetEnumerator() sembra per compilare bene - ma la pubblico IEnumerator<PriceLevel> dice che ho bisogno di un qualche tipo di cast - qual è il modo migliore per farlo?

William

+2

Perché? Perché usare un array per questo? – Oded

+1

'List' viene eseguito il backup da un array stesso, quindi non stai guadagnando nulla, tranne una complicazione eccessiva del tuo lavoro. – Tudor

+1

@Tudor a seconda di quale altra logica va nella classe, potrebbe essere più logico che 'PriceLevels' sia un array (ad esempio una dimensione fissa). Non c'è niente di sbagliato nel volerlo refactoring. –

risposta

14

Prova questo:

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

Il tipo può essere dedotto. '.AsEnumerable()' funziona bene. 'T []' implementa 'IEnumerable ', ma il suo metodo pubblico per 'GetEnumerator' restituisce un' IEnumerator' tipizzato debolmente. –

+0

@TimS. Hai assolutamente ragione! –

6

Come si può vedere dal tuo IEnumerable<T> implementazione, è necessario fornire sia una versione generica e non generica del metodo per soddisfare l'interfaccia. Per fare ciò, poiché i metodi hanno la stessa firma, uno di questi deve essere un'implementazione esplicita dell'interfaccia. Nel caso di List, la versione generica è un metodo nella classe e la versione non generica è una definizione di interfaccia esplicita, poiché la versione generica è generalmente più utile. Nel caso di un array, aveva già la versione non generica come implementazione e stava aggiungendo la versione generica del metodo in una versione successiva. Per evitare la violazione della modifica, la versione generica è invece la definizione dell'interfaccia esplicita.

Esistono diversi modi per risolvere questo problema. Qui ci sono tre semplici.

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 per la risposta più completa. – phoog

4

Cast T[] alla corrispondente IEnumerable<T>:

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

Secondo ECMA-335 Partizione I, §8.9.1, un tipo di vettore (array sola dimensione come T[]) implementa IList<T> che implica che essa implementa anche IEnumerable<T>. Tuttavia, l'implementazione dei metodi è esplicita, quindi è necessario utilizzare uno di questi:

Opzione 1: utilizzare semplicemente l'assegnazione implicita di array a IList<T>.

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

Opzione 2: Lasciare la variabile membro come matrice, e utilizzare il metodo AsEnumerable estensione. Questo metodo di estensione utilizza un'assegnazione implicita supportata che è preferibile utilizzare un cast diretto come (IEnumerable<PriceLevel>)PriceLevels.

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

Elementi da evitare:

  1. Il metodo Cast<T> introduce un controllo di tipo inutile per ogni elemento dell'array e deve essere evitato.
  2. Se è necessario includere solo elementi non null dall'enumerazione, è necessario utilizzare il metodo di estensione OfType<T>. In caso contrario, questo metodo introduce anche un controllo di tipo non necessario su ciascun elemento.
Problemi correlati