2010-06-28 13 views
9

Zawsze uważałem, że zwracanie tablic jest lepsze niż list z publicznym interfejsem API, ale wydaje się, że wszystkie funkcje są dostępne na listach dostępnych przez LINQ itp.jaki jest najlepszy typ kolekcji do zwrócenia w API

Czy zmieniła się tutaj najlepsza praktyka w zakresie zwracania kolekcji prymitywów lub przedmiotów?

na przykład:

Order[] GetOrders(); 
List<Order> GetOrders(); 
IEnumerable<Order> GetOrders(); 
IQueryable<Order> Get Orders(); 
+0

Należy zauważyć, że wszystkie powyższe typy obsługują Linq w różnym stopniu, poprzez 'IEnumerable ' lub 'IQueryable '. –

Odpowiedz

5

myślę najczęściej stosowanym typem jest IEnumerable<T>

  • z typem IEnumerable<T> powrotnej można użyć słowa kluczowego yield a to umożliwia opóźnione wyliczanie i wykonanie swojej metody . (Powszechną skargą jest na przykład to, że System.IO.Path.GetFiles() NIE zwraca wartości IEnumerable<T>, ale zwraca tablicę, co oznacza, że ​​po wywołaniu metody wszystkie elementy muszą zostać wyliczone, bez względu na to, czy są potrzebne, czy nie. masz taką samą wadą List<T>)
  • Większość metod rozszerzeń LINQ pracy na IEnumerable<T>
  • The IEnumerable<T> typ zwracany niczego konkretnego o rozmówcy nie zakładać. Jeśli osoba dzwoniąca potrzebuje listy lub tablicy, zawsze może ją utworzyć.
  • IEnumerable<T> jest implementowany przez List<T> i Array i dlatego jest łatwy do zmiany implementacji metody i nadal obsługuje poprzedni typ zwracania.
+0

Po prostu upewnij się, że nie pozwalasz komuś rzucić 'IEnumerable ' na przykład 'List ' i zmień go, jeśli złamałoby to niezmiennik klasy. Zobacz moją odpowiedź, aby uzyskać więcej informacji. –

5

Czy chcesz, aby kolekcja była niezmienna? IEnumerable<T> Mutowalne? IList<T>

Czy potrzebujesz indeksów? IList<T>

Z listy lub tablicy, konsument API ma pełną zdolność do dodawania, usuwania, usuwanie, jasne, itp

Posiadając IEnumerable<T> konsument API dostaje „worka” z pozycji, z żadnego konkretnego kolejność, brak indeksu i brak metod modyfikacji kolekcji.

Istnieje kilka ograniczonych okoliczności, w których warto zwrócić wartość IQueryable<T>, ale często są one charakterystyczne dla pojedynczych zapytań dotyczących budowania.

Ogólnie domyślnie byłby to IEnumerable<T>. Mogę użyć pola List<T> jako pola pomocniczego, ale chcę tylko pozwolić użytkownikowi na Add(), na przykład - nie usuwać, usuwać ani cokolwiek innego, dlatego deklaruję public void Add<T>(T item), który dodaje element do listy pola kopii.

+0

Nie zapomnij o ICollection , jeśli nie potrzebujesz indeksów. IList implementuje ICollection i po prostu dodaje podziałowe, IndexOf (pozycja T), Insert (int index, poz T) i RemoveAt (int index). –

1

Oprócz tego, co powiedzieli inni, chcę dodać, że nie powinieneś nigdy zwracać IQueryable, chyba że pobierasz obiekty z jakiegoś zdalnego źródła danych. IQueryable to obiekt zapytania , który pobiera wyniki w imieniu osoby dzwoniącej. Podczas korzystania z LINQ, IQuearyable zazwyczaj pobiera drzewo wyrażeń, które zostanie przetłumaczone do użycia przez inny system (np. Serwer SQL).

Aby uzyskać więcej informacji, patrz http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx.

5

Jak zwykle tylko powrócić niezmienne (żadnych modyfikacji) obiektów z właściwości/metod, odpowiedź ta zakłada, że ​​chcesz zrobić to samo.

Nie zapomnij o ReadOnlyCollection<T> który zwraca niezmienny kolekcji, które można jeszcze otworzyć przez indeks.

Jeśli używasz IEnumerable<T> i uwalniając swój typ na pustynię niekontrolowany, uważać na to:

:

class MyClass { 
    private List<int> _list; 
    public IEnumerable<int> Numbers { 
     get { return _list; } 
    } 
} 

Jako użytkownik może to i bałagan wewnętrzny stan swojej klasie zrobić

var list = (List<int>)myClass.Numbers; 
list.Add(123); 

To narusza intencję tylko do odczytu dla nieruchomości. W takich przypadkach, twoja rodzicielka powinna wyglądać następująco:

public IEnumerable<int> Numbers { 
     get { return new ReadOnlyCollection<int>(_list); } 
    } 

Alternatywnie można nazwać _list.ToReadOnly(). Napisałem go w całości, aby pokazać typ.

To powstrzyma każdego, kto zmieni twój stan (chyba że użyje refleksji, ale to naprawdę trudno zatrzymać, chyba że zbudujesz niezmienne kolekcje, takie jak te używane w wielu funkcjonalnych językach programowania, i to zupełnie inna historia).

Jeśli zwracasz kolekcję tylko do odczytu, lepiej będzie, gdy określisz członka jako ReadOnlyCollection<T>, ponieważ wtedy niektóre akcje będą działały szybciej (liczenie, dostęp do elementów według indeksu, kopiowanie do innej kolekcji).

Osobiście chciałbym zobaczyć ramy obejmują i wykorzystywać interfejs tak:

public interface IReadOnlyCollection<T> : IEnumerable<T> 
{ 
    T this[int index] { get; } 
    int Count { get; } 
    bool Contains(T item); 
    void CopyTo(T[] array, int arrayIndex); 
    int IndexOf(T item); 
} 

można uzyskać wszystkie te funkcje za pomocą metody rozszerzenie na górze IEnumerable<T> ale nie są one tak wydajnych.

Powiązane problemy