Czy powinienem zawsze zwracać liczbę mnogą zamiast liczby mnogiej?

Kiedy piszę mój DAL lub inny kod, który zwraca zestaw przedmiotów, powinienem zawsze złożyć oświadczenie o zwrocie:

public IEnumerable<FooBar> GetRecentItems()

Lub

public IList<FooBar> GetRecentItems()

Obecnie w moim kodzie staram się używać jak najwięcej, ale nie jestem pewien, czy jest to najlepsza praktyka? Wydawało się to słuszne, ponieważ zwracałem najbardziej ogólny typ danych, jednocześnie będąc opisowym tego, co robi, ale być może nie jest to poprawne.

Author: KingNestor, 2009-07-02

13 answers

To naprawdę zależy od tego, dlaczego używasz tego konkretnego interfejsu.

Na przykład, IList<T> ma kilka metod, które nie są obecne w IEnumerable<T>:

  • IndexOf(T item)
  • Insert(int index, T item)
  • RemoveAt(int index)

I Właściwości:

  • T this[int index] { get; set; }

Jeśli potrzebujesz tych metod w jakikolwiek sposób, to za wszelką cenę zwróć IList<T>.

Ponadto, jeśli metoda, która pochłania twój wynik IEnumerable<T> oczekuje IList<T>, uratuje CLR przed rozważeniem dowolnego wymagana konwersja, optymalizując w ten sposób skompilowany kod.

 40
Author: Jon Limjap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 08:31:46

Framework design guidelines zalecają użycie klasy Collection, gdy musisz zwrócić kolekcję, która może być modyfikowana przez wywołującego lub ReadOnlyCollection dla kolekcji tylko do odczytu.

Powodem, dla którego jest to preferowane od prostego IList, jest to, że IList nie informuje rozmówcy, czy jest tylko do odczytu, czy nie.

Jeśli zamiast tego zwrócisz IEnumerable<T>, pewne operacje mogą być nieco trudniejsze do wykonania przez wywołującego. Również nie będziesz już dawał rozmówcy elastyczność, aby modyfikować kolekcję, coś, czego możesz lub nie chcesz.

Należy pamiętać, że LINQ zawiera kilka sztuczek w rękawie i zoptymalizuje niektóre wywołania w oparciu o typ, na którym są wykonywane. Tak więc, na przykład, jeśli wykonasz zliczanie, a bazowa kolekcja jest listą, nie będzie ona przechodzić przez wszystkie elementy.

Osobiście, dla ORM prawdopodobnie zostałbym przy Collection<T> jako mojej wartości zwrotu.

 60
Author: Sam Saffron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-03 05:57:29

To zależy...

Zwrócenie typu least derived type (IEnumerable) pozostawi ci największą swobodę w zmianie implementacji bazowej w dół ścieżki.

Zwrócenie typu bardziej pochodnego (IList) zapewnia użytkownikom Twojego API więcej operacji na wyniku.

Zawsze sugerowałbym zwrócenie najmniej pochodnego typu, który ma wszystkie operacje, których będą potrzebować Twoi użytkownicy... więc w zasadzie, najpierw trzeba deremine jakie operacje na wyniku mają sens w kontekst definiowanego interfejsu API.

 19
Author: jerryjvl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 05:29:20

Ogólnie rzecz biorąc, powinieneś wymagać najbardziej ogólnej i zwrócić najbardziej konkretną rzecz, jaką możesz. Więc jeśli masz metodę, która pobiera parametr i naprawdę potrzebujesz tylko tego, co jest dostępne w IEnumerable, to powinien to być twój typ parametru. Jeśli twoja metoda może zwrócić IList lub IEnumerable, preferuj zwracanie IList. Zapewnia to, że jest on używany przez najszerszą gamę konsumentów.

Bądź luźny w tym, czego potrzebujesz, i wyraźny w tym, co zapewniasz.

 15
Author: Mel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-17 19:49:29

Należy wziąć pod uwagę, że jeśli do wygenerowania IEnumerable<T> używa się instrukcji LINQ deferred-execution, wywołanie .ToList() przed powrotem z metody oznacza, że elementy mogą zostać powtórzone dwa razy - raz w celu utworzenia listy i raz, gdy wywołanie wywołania przenika, filtruje lub przekształca zwracaną wartość. Kiedy jest to praktyczne, Lubię unikać konwersji wyników LINQ-to-Objects na konkretną listę lub Słownik, dopóki nie będę musiał. Jeśli mój rozmówca potrzebuje listy, jest to jedna łatwa metoda połączenia away - Nie muszę podejmować tej decyzji za nich, a to sprawia, że mój kod jest nieco bardziej wydajny w przypadkach, gdy dzwoniący właśnie robi foreach.

 8
Author: Joel Mueller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-21 15:00:12

List<T> oferuje kod wywołujący o wiele więcej funkcji, takich jak modyfikowanie zwracanego obiektu i dostęp przez indeks. Więc pytanie sprowadza się do: w konkretnym przypadku zastosowania aplikacji, czy chcesz wspierać takie zastosowania (prawdopodobnie zwracając świeżo skonstruowaną kolekcję!), dla wygody rozmówcy - czy chcesz prędkości dla prostego przypadku, gdy wszystko, czego potrzebuje rozmówca, to pętla przez kolekcję i możesz bezpiecznie zwrócić odniesienie do prawdziwej kolekcji bazowej bez obawiając się, że spowoduje to błędną zmianę itp.?

Tylko Ty możesz odpowiedzieć na to pytanie i tylko dobrze zrozumieć, co Twoi rozmówcy będą chcieli zrobić z wartością zwracaną i jak ważna jest tutaj wydajność (jak duże są zbiory, które kopiujesz, jak prawdopodobne jest to wąskie gardło itp.).

 7
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 05:28:08

Myślę, że można użyć albo, ale każdy ma zastosowanie. Zasadniczo List jest IEnumerable ale masz funkcja count, add element, remove element

IEnumerable nie jest wydajny do liczenia elementów

Jeśli zbiór ma być tylko do odczytu, lub modyfikacja zbioru jest kontrolowana przez Parent, to zwracanie IList tylko dla Count nie jest dobrym pomysłem.

W Linq istnieje metoda rozszerzenia Count() na IEnumerable<T>, która wewnątrz CLR będzie skrótem do .Count jeśli podstawowy typ jest IList, więc różnica w wydajności jest znikoma.

Ogólnie uważam, że (opinia) lepiej jest zwracać ilościowo tam, gdzie to możliwe, jeśli trzeba zrobić uzupełnienia, to dodać te metody do klasy nadrzędnej, w przeciwnym razie konsument zarządza kolekcją w modelu, który narusza zasady, np. manufacturer.Models.Add(model) narusza prawo demeter. Oczywiście są to tylko wytyczne, a nie twarde i szybkie zasady, ale dopóki nie masz pełnego chwyty stosowalności, podążanie ślepo jest lepsze niż nie podążanie w ogóle.

public interface IManufacturer 
{
     IEnumerable<Model> Models {get;}
     void AddModel(Model model);
}

(Uwaga: Jeśli używasz nNHibernate, może być konieczne mapowanie do prywatnej listy IList przy użyciu różnych accesorów.)

 4
Author: Rashmi Pandit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-22 03:10:01

Nie jest to takie proste, gdy mówimy o wartościach zwracanych zamiast parametrów wejściowych. Gdy jest to parametr wejściowy, wiesz dokładnie, co musisz zrobić. Tak więc, jeśli chcesz być w stanie iterować nad kolekcją, bierzesz IEnumberable, podczas gdy jeśli chcesz dodać lub usunąć, bierzesz IList.

W przypadku wartości zwracanej jest to trudniejsze. Czego oczekuje twój rozmówca? Jeśli zwrócisz liczbę mnogą, wtedy nie będzie wiedział a priori, że może zrobić z tego Ilistę. Ale, jeśli zwrócisz Ilistę, będzie wiedział, że może ją powtórzyć. Musisz więc wziąć pod uwagę, co twój rozmówca zrobi z danymi. Funkcjonalność, której potrzebuje/oczekuje twój rozmówca, jest tym, co powinno rządzić przy podejmowaniu decyzji o powrocie.

 1
Author: JP Alioto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 05:28:59

Jak wszyscy mówili To zależy, jeśli nie chcesz dodawać/usuwać functioanlity przy wywołaniu warstwy to zagłosuję na Ieenumerable, ponieważ zapewnia tylko iterację i podstawową funkcjonalność, która w projektowaniu mi się podoba. Wracając IList moje głosy są zawsze ponownie, ale to głównie to, co lubisz, a co nie. pod względem wydajności myślę, że są one bardziej takie same.

 0
Author: Usman Masood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 05:34:45

Jeśli nie liczysz w swoim zewnętrznym kodzie, zawsze lepiej jest zwrócić IEnumerable, ponieważ później możesz zmienić swoją implementację (bez wpływu zewnętrznego kodu), na przykład dla yield iterator logiki i oszczędzać zasoby pamięci (przy okazji bardzo dobra cecha językowa).

Jeśli jednak potrzebujesz liczby elementów, nie zapominaj, że istnieje inna warstwa pomiędzy IEnumerable i IList - ICollection .

 0
Author: arbiter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 07:31:30

Może jestem trochę za daleko, widząc, że nikt inny nie zasugerował tego do tej pory, ale dlaczego nie zwrócisz (I)Collection<T>?

Z tego, co pamiętam, Collection<T> był preferowanym typem zwracania zamiast List<T>, ponieważ abstrakuje implementację. Wszystkie implementują IEnumerable, ale brzmi to dla mnie trochę zbyt nisko jak na tę pracę.

 0
Author: Tiberiu Ana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 07:48:29

Myślę, że można użyć albo, ale każdy ma zastosowanie. Zasadniczo List jest IEnumerable ale masz funkcję liczenia, dodawania elementu, usuwania elementu

IEnumerable nie nadaje się do liczenia elementów, ani do uzyskania określonego elementu w zbiorze.

List jest kolekcją, która idealnie nadaje się do znajdowania konkretnych elementów, łatwego dodawania elementów lub ich usuwania.

Generalnie staram się używać List tam, gdzie to możliwe, ponieważ daje mi to większą elastyczność.

Użycie List<FooBar> getRecentItems() raczej niż IList<FooBar> GetRecentItems()

 0
Author: Stuart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-21 15:00:58

Myślę, że ogólną zasadą jest użycie bardziej specyficznej klasy do powrotu, aby uniknąć wykonywania niepotrzebnej pracy i dać rozmówcy więcej opcji.

To powiedziawszy, myślę, że ważniejsze jest rozważenie kodu przed tobą, który piszesz, niż kodu, który napisze następny facet (w granicach rozsądku.) Dzieje się tak dlatego, że można wprowadzać założenia co do kodu, który już istnieje.

Pamiętaj, że przejście do kolekcji z IEnumerable w interfejsie zadziała, Przejście W dół do Liczba mnoga z kolekcji spowoduje złamanie istniejącego kodu.

Jeśli wszystkie te opinie wydają się sprzeczne, to dlatego, że decyzja jest subiektywna.

 0
Author: Sprague,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-04 14:39:25