2012-07-03 18 views
11

Jest to prawdopodobnie proste pytanie składniowe, ale nie mogę tego zrozumieć.Implementacja IEnumerable with Array

Normalnie, chciałbym to zrobić:

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

Ale zamiast listy, chcę używać tablicy - tak:

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

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

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

IEnumerator IEnumerable.GetEnumerator() wydaje się skompilować w porządku - ale publiczna IEnumerator<PriceLevel> mówi, że potrzebuję pewnego rodzaju obsady - jaki jest najlepszy sposób na zrobienie tego?

William

+2

Dlaczego? Po co używać tej tablicy? – Oded

+1

'List' jest zapisywany przez samą tablicę, więc nic nie zyskujesz, z wyjątkiem nadmiernej komplikacji twojej pracy. – Tudor

+1

@Dziecko w zależności od tego, jaką inną logikę znajdziemy w klasie, może to mieć więcej sensu, jeśli 'PriceLevels' będzie tablicą (na przykład o stałym rozmiarze). Nic złego w tym, że chcesz to zmienić. –

Odpowiedz

14

Spróbuj tego:

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

Typ można wywnioskować. '.AsEnumerable()' działa dobrze. 'T []' implementuje 'IEnumerable ', ale jego publiczna metoda 'GetEnumerator' zwraca słabo wypisane' IEnumerator'. –

+0

@TimS. Masz całkowitą rację! –

6

Jak widać z własnego IEnumerable<T> realizacji, trzeba zapewnić zarówno ogólny i nierodzajową wersję sposobu wypełnienia interfejs. Aby to zrobić, ponieważ metody mają ten sam podpis, jedna z nich musi być jawną implementacją interfejsu. W przypadku wersji List wersja ogólna jest metodą w klasie, a wersja nietypowa jest jawną definicją interfejsu, ponieważ wersja ogólna jest generalnie bardziej użyteczna. W przypadku tablicy miała już nietypową wersję jako implementację i dodawała ogólną wersję metody w kolejnej wersji. Aby uniknąć zmiany, wersja ogólna jest zamiast niej jawną definicją interfejsu.

Istnieje wiele sposobów rozwiązania tego problemu. Oto trzy proste.

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, aby uzyskać najbardziej wyczerpującą odpowiedź. – phoog

4

Odlewanie T[] do odpowiedniego IEnumerable<T>:

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

Według ECMA 335 podziału I §8.9.1, typ wektora (tablica pojedynczy wymiar jak T[]) realizuje IList<T> która nakłada również implementuje IEnumerable<T>. Jednak implementacja metod jest jednoznaczna, więc musisz użyć jednego z następujących:

Opcja 1: Po prostu użyj domyślnego przypisania tablic do IList<T>.

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

Opcja 2: Pozostawić zmienną składową w tablicy i użyć metody AsEnumerable wewnętrzny. Ta metoda rozszerzeń korzysta z obsługiwanego, niejawnego przypisania, które jest preferowane w przypadku bezpośredniego odlewania, takiego jak (IEnumerable<PriceLevel>)PriceLevels.

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

Rzeczy należy unikać:

  1. Sposób Cast<T> wprowadza niepotrzebnego sprawdzania typu dla każdego elementu tablicy i należy ich unikać.
  2. Jeśli do wyliczenia należy dołączyć tylko elementy inne niż NULL, można użyć metody rozszerzającej OfType<T>. W przeciwnym razie ta metoda wprowadza także niepotrzebne sprawdzenie typu dla każdego elementu.