Nie wiem, który typ kolekcji powinienem zwrócić z moich publicznych metod i właściwości interfejsu API.
Zbiory, które mam na myśli to IList
, ICollection
i Collection
.
Czy zwrot jednego z tych typów jest zawsze preferowany względem innych, czy też zależy to od konkretnej sytuacji?
c#
.net
generics
collections
Rocky Singh
źródło
źródło
Odpowiedzi:
Ogólnie powinieneś zwrócić typ, który jest jak najbardziej ogólny, tj. Taki, który zna wystarczająco dużo zwróconych danych, których konsument musi użyć. W ten sposób masz większą swobodę zmiany implementacji API bez przerywania kodu, który go używa.
Rozważ również
IEnumerable<T>
interfejs jako typ zwracany. Jeśli wynik ma być tylko iterowany, konsument nie potrzebuje więcej.źródło
Count
metody sprawdza rzeczywisty typ kolekcji, więc użyje właściwościLength
lubCount
dla niektórych znanych typów, takich jak tablice, aICollection
nawet jeśli podasz ją jako plikIEnumerable
.Thing<T>
implementuje,IList<T>
ale nie jest nieogólnaICollection
, to wywołanieIEnumerable<Cat>.Count()
aThing<Cat>
byłoby szybkie, ale wywołanieIEnumerable<Animal>.Count()
byłoby wolne (ponieważ metoda rozszerzenia szukałaby implementacjiICollection<Cat>
). Jeśli jednak klasa implementuje nieogólnąICollection
,IEnumerable<Animal>.Count
to znajdzie i użyje tego.ICollection<T>
jest interfejs, który ujawnia semantykę kolekcji, takich jakAdd()
,Remove()
iCount
.Collection<T>
jest konkretną implementacjąICollection<T>
interfejsu.IList<T>
jest zasadniczoICollection<T>
z dostępem opartym na kolejności losowej.W takim przypadku powinieneś zdecydować, czy Twoje wyniki wymagają semantyki listy, takiej jak indeksowanie na podstawie kolejności (następnie użyj
IList<T>
), czy też po prostu musisz zwrócić nieuporządkowany „pakiet” wyników (następnie użyjICollection<T>
).źródło
Collection<T>
narzędziaIList<T>
i nie tylkoICollection<T>
.IEnumerable<T>
są uporządkowane. Co odróżniaIList<T>
odICollection<T>
jest to, że oferuje członków do pracy z indeksami. Na przykładlist[5]
działa, alecollection[5]
się nie kompiluje.IList<T>
. Istnieje wiele uporządkowanych kolekcji, które tego nie robią.IList<T>
chodzi o szybki dostęp indeksowany.IEnumerable<T>
są uporządkowane? WeźHashSet<T>
- wdraża,IEnumerable<T>
ale wyraźnie nie jest zamówiony. Oznacza to, że nie masz wpływu na kolejność elementów i ta kolejność może się zmienić w dowolnym momencie, jeśli wewnętrzna tabela skrótów zostanie ponownie zorganizowana.Główna różnica między
IList<T>
iICollection<T>
polega na tym, żeIList<T>
umożliwia dostęp do elementów za pośrednictwem indeksu.IList<T>
opisuje typy tablicowe.ICollection<T>
Dostęp do elementów w an można uzyskać tylko poprzez wyliczenie. Oba pozwalają na wstawianie i usuwanie elementów.Jeśli potrzebujesz tylko wyliczyć kolekcję,
IEnumerable<T>
to należy preferować. Ma dwie zalety w stosunku do innych:Nie zezwala na zmiany w kolekcji (ale nie w elementach, jeśli są typu referencyjnego).
Pozwala na największą możliwą różnorodność źródeł, w tym wyliczenia, które są generowane algorytmicznie i wcale nie są kolekcjami.
Collection<T>
jest klasą bazową, która jest przydatna głównie dla implementatorów kolekcji. Jeśli ujawnisz go w interfejsach (API), wiele przydatnych kolekcji, które nie pochodzą z niego, zostanie wykluczonych.Jedną z wad
IList<T>
jest to, że tablice go implementują, ale nie pozwalają na dodawanie ani usuwanie elementów (tj. Nie można zmienić długości tablicy). W przypadku wywołaniaIList<T>.Add(item)
tablicy zostanie zgłoszony wyjątek . Sytuacja jest nieco rozwiązana, ponieważIList<T>
ma właściwość logicznąIsReadOnly
, którą można sprawdzić przed podjęciem próby. Ale moim zdaniem to wciąż wada projektowa w bibliotece . Dlatego korzystamList<T>
bezpośrednio, gdy wymagana jest możliwość dodania lub usunięcia pozycji.źródło
Collection
,ReadOnlyCollection
lubKeyedCollection
. IList
nie należy tego zwracać.IList<T>
, nie ma możliwości zapewnienia, że metoda nie zostanie wywołana z tablicą jako parametrem.IList<T>
jest podstawowym interfejsem dla wszystkich list ogólnych. Ponieważ jest to zbiór uporządkowany, implementacja może decydować o kolejności, od sortowania po zamówienie reklamowe. PonadtoIlist
posiada właściwość Item, która umożliwia metodom odczytywanie i edycję wpisów na liście na podstawie ich indeksu. Umożliwia to wstawianie, usuwanie wartości do / z listy w indeksie pozycji.Ponieważ
IList<T> : ICollection<T>
wszystkie metody zICollection<T>
są również dostępne tutaj do implementacji.ICollection<T>
jest podstawowym interfejsem dla wszystkich kolekcji ogólnych. Definiuje rozmiar, moduły wyliczające i metody synchronizacji. Możesz dodać lub usunąć element do kolekcji, ale nie możesz wybrać, w którym miejscu ma to nastąpić z powodu braku właściwości index.Collection<T>
stanowi implementacjęIList<T>
,IList
iIReadOnlyList<T>
.Jeśli używasz węższego typu interfejsu, takiego jak
ICollection<T>
zamiastIList<T>
, chronisz kod przed wprowadzaniem zmian. Jeśli używasz szerszego typu interfejsu, takiego jakIList<T>
, istnieje większe ryzyko zerwania zmian w kodzie.Cytowanie ze źródła ,
źródło
Zwracanie typu interfejsu jest bardziej ogólne, więc (brak dalszych informacji na temat twojego konkretnego przypadku użycia) skłaniałbym się ku temu. Jeśli chcesz udostępnić obsługę indeksowania, wybierz
IList<T>
, w przeciwnym razieICollection<T>
wystarczy. Na koniec, jeśli chcesz wskazać, że zwracane typy są tylko do odczytu, wybierzIEnumerable<T>
.A jeśli wcześniej tego nie czytaliście, Brad Abrams i Krzysztof Cwalina napisali świetną książkę zatytułowaną „Wytyczne dotyczące projektowania ram: konwencje, idiomy i wzorce dla bibliotek .NET wielokrotnego użytku” (podsumowanie można pobrać stąd ).
źródło
IEnumerable<T>
jest tylko do odczytu? Jasne, ale po ponownym uruchomieniu go w kontekście repozytorium, nawet po wykonaniu ToList nie jest bezpieczny wątkowo. Problem polega na tym, że oryginalne źródło danych pobiera GC, a IEnumarble.ToList () nie działa w kontekście wielowątkowym. Działa na liniowym, ponieważ GC jest wywoływane po wykonaniu pracy, ale używanieasync
teraz dni w 4.5+ IEnumarbale staje się bólem piłki.Jest kilka tematów, które wynikają z tego pytania:
Możesz chcieć podkreślić, że jest to API zorientowane obiektowo
interfejsy a klasy
Jeśli nie masz dużego doświadczenia z interfejsami, polecam pozostać przy zajęciach. Widzę wiele razy deweloperów skaczących do interfejsów, nawet jeśli nie jest to konieczne.
I koniec z kiepskim projektem interfejsu, zamiast dobrym projektem klasowym, który, nawiasem mówiąc, może ostatecznie zostać przeniesiony do dobrego projektu interfejsu ...
Zobaczysz wiele interfejsów w API, ale nie spiesz się, jeśli tego nie potrzebujesz.
W końcu nauczysz się, jak stosować interfejsy w swoim kodzie.
która konkretna klasa, z kilku podobnych klas, kolekcji, listy, tablicy?
Istnieje kilka klas w języku C # (dotnet), które można wymieniać. Jak już wspomniano, jeśli potrzebujesz czegoś z bardziej specyficznej klasy, takiej jak „CanBeSortedClass”, wyraź to w swoim API.
Czy twój użytkownik API naprawdę musi wiedzieć, że twoją klasę można posortować lub zastosować jakiś format do elementów? Następnie użyj „CanBeSortedClass” lub „ElementsCanBePaintedClass”, w przeciwnym razie użyj „GenericBrandClass”.
W przeciwnym razie użyj bardziej ogólnej klasy.
Typowe klasy kolekcji a kolekcje podelementów („ogólne”)
Przekonasz się, że istnieją klasy zawierające inne elementy i możesz określić, że wszystkie elementy powinny być określonego typu.
Kolekcje ogólne to te klasy, których można używać tej samej kolekcji dla kilku aplikacji kodujących, bez konieczności tworzenia nowej kolekcji, dla każdego nowego typu elementu podrzędnego, na przykład: Collection .
Czy Twój użytkownik API będzie potrzebował bardzo konkretnego typu, takiego samego dla wszystkich elementów?
Użyj czegoś takiego jak
List<WashingtonApple>
.Czy Twój użytkownik API będzie potrzebował kilku powiązanych typów?
Wystawiać
List<Fruit>
do API i użyćList<Orange>
List<Banana>
,List<Strawberry>
wewnętrznie, gdzieOrange
,Banana
iStrawberry
są potomkamiFruit
.Czy Twój użytkownik interfejsu API będzie potrzebował kolekcji typów ogólnych?
Użyj
List
tam, gdzie znajdują się wszystkie elementyobject
.Twoje zdrowie.
źródło