Lista lub IList [zamknięta]

Zamknięte . To pytanie jest oparte na opinii . Obecnie nie przyjmuje odpowiedzi.

Chcesz poprawić to pytanie? Zaktualizuj pytanie, aby mogło być odpowiedź z faktami i cytatami przez edytując ten post .

Zamknięte 1 rok temu .

Popraw to pytanie

Czy ktoś może mi wyjaśnić dlaczego chciałbym używać IList zamiast List w C#?

podobne pytanie: dlaczego uważa się za złe ujawnianie List<T>

Author: Community, 2008-12-30

18 answers

Jeśli wystawiasz swoją klasę za pomocą biblioteki, której używają inni, zazwyczaj chcesz ją wystawiać za pomocą interfejsów, a nie konkretnych implementacji. Pomoże to, jeśli zdecydujesz się później zmienić implementację swojej klasy, aby użyć innej konkretnej klasy. W takim przypadku użytkownicy biblioteki nie będą musieli aktualizować swojego kodu, ponieważ interfejs się nie zmienia.

Jeśli używasz go tylko wewnętrznie, możesz nie przejmować się tak bardzo, A używanie List<T> może być w porządku.

 460
Author: tvanfosson,
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-02-24 17:51:36

Mniej popularną odpowiedzią jest to, że programiści lubią udawać, że ich oprogramowanie będzie ponownie używane na całym świecie, kiedy w rzeczywistości większość projektów będzie utrzymywana przez niewielką ilość ludzi i jakkolwiek ładne są soundbity związane z interfejsem, to się łudzisz.

Astronauci Architektury . Szanse, że kiedykolwiek napiszesz swój własny IList, który dodaje coś do tych już w. NET framework są tak odległe, że jest to teoretyczna galaretka zarezerwowana dla " najlepszych praktyki".

Oprogramowanie

Oczywiście, jeśli jesteś pytany, którego używasz w wywiadzie, mówisz IList, uśmiechasz się i oboje wyglądają na zadowolonych z siebie za to, że jesteście tacy sprytni. Lub dla publicznego API, IList. Mam nadzieję, że rozumiesz o co mi chodzi.

 337
Author: Arec Barrwin,
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
2017-02-08 14:16:00

Interfejs jest obietnicą (lub kontraktem).

Jak zawsze z obietnicami - im mniejsze tym lepsze .

 191
Author: Rinat Abdullin,
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
2008-12-30 18:22:10

Niektórzy mówią " Zawsze używaj IList<T> zamiast List<T>".
Chcą, abyś zmienił sygnatury swojej metody z void Foo(List<T> input) na void Foo(IList<T> input).

Ci ludzie się mylą. To bardziej niuansowe. Jeśli zwracasz IList<T> jako część publicznego interfejsu do swojej biblioteki, zostawiasz sobie interesujące opcje, aby być może w przyszłości utworzyć własną listę. Możesz nigdy nie potrzebować tej opcji, ale to argument. Myślę, że to cały argument za zwróceniem interfejsu zamiast betonu. Warto o tym wspomnieć, ale w tym przypadku ma to poważną wadę. W 1999 roku, w wyniku połączenia z firmą Cushman & Wakefield, powstała firma Cushman & Wakefield, która powstała w 1999 roku.]}

Ale co ważniejsze, {[50] } Jeśli akceptujesz IList jako parametr, lepiej bądź ostrożny, ponieważ IList<T> i List<T> nie zachowują się tak samo. Pomimo podobieństwa nazwy i pomimo dzielenia interfejsu robią Nie ujawniać tę samą } umowę .

Załóżmy, że masz tę metodę:

public Foo(List<int> a)
{
    a.Add(someNumber);
}

Pomocny kolega "refakturuje" metodę przyjmowania IList<int>.

Twój kod jest teraz uszkodzony, ponieważ int[] implementuje IList<int>, ale ma stały rozmiar. Kontrakt dla ICollection<T> (baza IList<T>) wymaga kodu, który go używa, aby sprawdzić flagę IsReadOnly przed próbą dodania lub usunięcia przedmiotów z kolekcji. Umowa na List<T> nie.

Liskov Zasada substytucji (uproszczona) stanowi, że typ Pochodny powinien być stosowany zamiast typu bazowego, bez dodatkowych warunków wstępnych lub warunków postkondensacyjnych.

To łamie zasadę substytucji Liskowa.
 int[] array = new[] {1, 2, 3};
 IList<int> ilist = array;

 ilist.Add(4); // throws System.NotSupportedException
 ilist.Insert(0, 0); // throws System.NotSupportedException
 ilist.Remove(3); // throws System.NotSupportedException
 ilist.RemoveAt(0); // throws System.NotSupportedException

Ale tak nie jest. odpowiedź na to jest taka, że przykład użyty IList / ICollection jest błędny. Jeśli używasz ICollection musisz sprawdzić flagę IsReadOnly.

if (!ilist.IsReadOnly)
{
   ilist.Add(4);
   ilist.Insert(0, 0); 
   ilist.Remove(3);
   ilist.RemoveAt(0);
}
else
{
   // what were you planning to do if you were given a read only list anyway?
}

Jeśli ktoś poda ci tablicę lub listę, Twój kod będzie działać dobrze, jeśli za każdym razem sprawdzasz flagę i masz awaryjny... Ale naprawdę; kto tak robi? Nie wiesz z góry, czy Twoja metoda potrzebuje listy, która może przyjąć dodatkowych członków; nie podajesz tego w podpisie metody? Co dokładnie miałbyś zamiar zrobić, gdybyś otrzymał listę tylko do odczytu, taką jak int[]?

Możesz zastąpić List<T> kodem, który używa IList<T>/ICollection<T> poprawnie . Nie możesz zagwarantować, że możesz zastąpić IList<T>/ICollection<T> do kodu który używa List<T>.

Jest odwołanie się do zasady pojedynczej odpowiedzialności / zasady segregacji interfejsu w wielu argumentach, aby używać abstrakcji zamiast konkretnych typów-zależy od najwęższego możliwego interfejsu. W większości przypadków, jeśli używasz List<T> i uważasz, że możesz użyć Węższego interfejsu - dlaczego nie IEnumerable<T>? Jest to często lepsze dopasowanie, Jeśli nie musisz dodawać przedmiotów. Jeśli chcesz dodać do kolekcji, użyj typu Beton, List<T>.

Dla mnie IList<T> (i ICollection<T>) jest najgorszą częścią. NET framework. IsReadOnly łamie zasadę najmniejszego zaskoczenia. Klasa, taka jak Array, która nigdy nie pozwala na dodawanie, wstawianie lub usuwanie elementów, nie powinna implementować interfejsu z metodami Add, Insert i Remove. (Zobacz też https://softwareengineering.stackexchange.com/questions/306105/implementing-an-interface-when-you-dont-need-one-of-the-properties)

Czy IList<T> dobrze pasuje do Twojej organizacji? Jeśli kolega poprosi Cię o zmianę podpisu metody na IList<T> zamiast List<T>, zapytaj go, jak dodałby element do IList<T>. Jeśli nie wiedzą o IsReadOnly (a większość ludzi nie wie), nie używaj IList<T>. Nigdy.


Zauważ, że flaga IsReadOnly pochodzi Zkolekcji i wskazuje, czy elementy mogą być dodawane lub usuwane z kolekcji; ale aby naprawdę zdezorientować rzeczy, nie wskazuje, czy można je zastąpić, co w przypadku tablic (które zwracają IsReadOnlys = = true) może być.

Aby dowiedzieć się więcej o IsReadOnly, zobacz definicja MSDN ICollection.IsReadOnly

 104
Author: perfectionist,
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
2019-06-18 10:29:41

List<T> jest specyficzną implementacją IList<T>, która jest kontenerem, który może być zaadresowany tak samo jak tablica liniowa T[] za pomocą indeksu całkowitego. Gdy określisz IList<T> jako typ argumentu metody, określisz tylko, że potrzebujesz pewnych możliwości kontenera.

Na przykład Specyfikacja interfejsu nie wymusza użycia określonej struktury danych. Implementacja List<T> ma taką samą wydajność w zakresie dostępu, usuwania i dodawania elementy jako tablica liniowa. Można jednak wyobrazić sobie implementację, która jest wspierana przez połączoną listę, dla której dodawanie elementów do końca jest tańsze (stały czas), ale dostęp losowy znacznie droższy. (Zauważ, że.NET LinkedList<T> robi , a nie implementuje IList<T>.)

Ten przykład mówi również, że mogą być sytuacje, w których musisz określić implementację, a nie Interfejs, na liście argumentów: w tym przykładzie, gdy potrzebujesz określonego dostępu charakterystyka wydajności. Jest to zwykle gwarantowane dla konkretnej implementacji kontenera (dokumentacjaList<T>: "implementuje ogólny interfejs IList<T> za pomocą tablicy, której rozmiar jest dynamicznie zwiększany zgodnie z wymaganiami.").

Dodatkowo, warto rozważyć ujawnienie najmniej funkcjonalności, których potrzebujesz. Na przykład. jeśli nie musisz zmieniać zawartości listy, prawdopodobnie powinieneś rozważyć użycie IEnumerable<T>, które IList<T> rozszerza.

 37
Author: ILoveFortran,
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-09-11 19:10:09

Chciałbym nieco odwrócić pytanie, zamiast uzasadniać, dlaczego powinieneś używać interfejsu zamiast konkretnej implementacji, spróbuj uzasadnić, dlaczego chcesz użyć konkretnej implementacji, a nie interfejsu. Jeśli nie możesz tego uzasadnić, Użyj interfejsu.

 28
Author: Patrik Hägne,
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-09-08 21:47:31

IList jest interfejsem, więc możesz dziedziczyć inną klasę i nadal implementować IList, podczas gdy dziedziczenie listy uniemożliwia ci to.

Na przykład, jeśli istnieje Klasa A i twoja klasa b dziedziczy ją, to nie możesz użyć listy

class A : B, IList<T> { ... }
 19
Author: Diadistis,
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
2008-12-30 12:23:19

Zasadą TDD i OOP jest zwykle Programowanie do interfejsu, a nie implementacji.

W tym konkretnym przypadku, ponieważ zasadniczo mówisz o konstrukcji języka, a nie niestandardowej, to ogólnie nie ma znaczenia, ale powiedzmy na przykład, że lista nie obsługuje czegoś, czego potrzebujesz. Jeśli użyłeś IList w pozostałej części aplikacji, możesz rozszerzyć Listę o własną klasę niestandardową i nadal być w stanie przekazać ją bez refaktoryzacji.

The cost to do this jest minimalne, dlaczego nie oszczędzić sobie bólu głowy później? Na tym polega zasada interfejsu.

 15
Author: annakata,
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
2008-12-30 12:26:02
public void Foo(IList<Bar> list)
{
     // Do Something with the list here.
}

W tym przypadku można przejść do dowolnej klasy, która implementuje interfejs IList . Jeśli zamiast tego użyłeś List, tylko instancja List może zostać przekazana.

Droga IList jest luźniej sprzężona niż droga List .

 15
Author: smack0007,
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
2008-12-30 13:35:00

Najważniejszy przypadek użycia interfejsów nad implementacjami znajduje się w parametrach twojego API. Jeśli twój API pobiera parametr List, to każdy, kto go używa, musi go użyć. Jeśli parametr type jest IList, to wywołujący ma znacznie większą swobodę i może używać klas, o których nigdy nie słyszałeś, które mogły nawet nie istnieć, gdy twój kod został napisany.

 14
Author: Michael Borgwardt,
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
2008-12-30 13:35:37

Przypuśćmy, że żadne z tych pytań listy vs IList (lub odpowiedzi) nie wspomina o różnicy w podpisie. (Dlatego Szukałem tego pytania na SO!)

Oto metody zawarte w liście, których nie można znaleźć w IList, przynajmniej od. NET 4.5 (ok. 2015)

  • AddRange
  • AsReadOnly
  • BinarySearch
  • Pojemność
  • ConvertAll
  • Istnieje
  • Znajdź
  • FindAll
  • FindIndex
  • FindLast
  • FindLastIndex
  • ForEach
  • GetRange
  • InsertRange
  • LastIndexOf
  • RemoveAll
  • RemoveRange
  • rewers
  • Sortuj
  • ToArray
  • TrimExcess
  • TrueForAll
 14
Author: JasonS,
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
2015-10-18 17:53:03

Co jeśli. NET 5.0 zastąpi System.Collections.Generic.List<T> na System.Collection.Generics.LinearList<T>. . NET zawsze posiada nazwę List<T>, ale gwarantuje, że IList<T> jest umową. Więc IMHO my (przynajmniej ja) nie powinniśmy używać czyjegoś nazwiska (choć w tym przypadku jest to. NET) i wpadać w kłopoty później.

W przypadku użycia IList<T>, wywołujący zawsze ma gwarancję działania, a Wykonawca może dowolnie zmienić bazowy zbiór na dowolną alternatywną konkretną implementację IList

 7
Author: Soundararajan,
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-09-11 19:11:03

Wszystkie koncepcje są zasadniczo podane w większości powyższych odpowiedzi na temat Dlaczego używać interfejsu zamiast konkretnych implementacji.

IList<T> defines those methods (not including extension methods)

IList<T> MSDN link

  1. Dodaj
  2. Wyczyść
  3. zawiera
  4. CopyTo
  5. GetEnumerator
  6. IndexOf
  7. Insert
  8. Usuń
  9. RemoveAt

List<T> implementuje te dziewięć metod (nie wliczając metod rozszerzeń), ponadto posiada około 41 metod publicznych, który waży pod uwagę, który z nich użyć w aplikacji.

List<T> MSDN link

 7
Author: yantaq,
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-08-26 14:20:33

Zrobiłbyś to, ponieważ zdefiniowanie IList lub ICollection otworzyłoby się na inne implementacje Twoich interfejsów.

Możesz chcieć mieć IOrderRepository, które definiuje zbiór zleceń w IList lub ICollection. Możesz wtedy mieć różne rodzaje implementacji, aby dostarczyć listę zamówień, o ile są one zgodne z "regułami" zdefiniowanymi przez Twoją listę Lubkolekcję.

 4
Author: Peter Lindholm,
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
2015-02-10 23:40:27

IList jest prawie zawsze preferowany zgodnie z poradą innego plakatu, jednak zauważ istnieje błąd w.NET 3.5 sp 1 podczas uruchamiania IList przez więcej niż jeden cykl serializacji / deserializacji za pomocą DataContractSerializer WCF.

Jest teraz SP aby naprawić ten błąd: KB 971030

 3
Author: StuartLC,
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-02-07 10:58:39

interfejs zapewnia, że przynajmniej uzyskasz metody, których oczekujesz; świadomość definicji interfejsu tj. wszystkie abstrakcyjne metody, które mają być zaimplementowane przez dowolną klasę dziedziczącą interfejs. więc jeśli ktoś tworzy ogromną klasę z kilkoma metodami oprócz tych, które odziedziczył po interfejsie dla niektórych funkcji dodawania, a te są bezużyteczne dla Ciebie, lepiej użyć odniesienia do podklasy (w tym przypadku interfejs) i przypisać do niego konkretny obiekt klasy.

Dodatkową zaletą jest to, że Twój kod jest bezpieczny przed wszelkimi zmianami w klasie concrete, ponieważ subskrybujesz tylko kilka metod klasy concrete i są to te, które będą tam tak długo, jak Klasa concrete dziedziczy z używanego interfejsu. więc jego bezpieczeństwo dla Ciebie i wolność dla kodera, który pisze konkretne wdrożenie, aby zmienić lub dodać więcej funkcjonalności do swojej konkretnej klasy.

 2
Author: vishy,
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
2010-07-27 12:04:37

Możesz spojrzeć na ten argument pod kilkoma kątami, włączając w to podejście czysto OO, które mówi, aby programować przeciwko interfejsowi, a nie implementacji. Z tą myślą korzystanie z IList odbywa się zgodnie z tą samą zasadą, co przekazywanie i używanie interfejsów, które definiujesz od podstaw. Wierzę również w czynniki skalowalności i elastyczności dostarczane przez interfejs w ogóle. Jeśli Klasa implementująca IList wymaga rozszerzenia lub zmiany, kod zużywający się nie musi zmieniać; wie, do czego stosuje się kontrakt interfejsu IList. Jednak użycie konkretnej implementacji i listy na klasie, która się zmienia, może spowodować konieczność zmiany kodu wywołującego. Dzieje się tak, ponieważ Klasa przylegająca do IList gwarantuje pewne zachowanie, które nie jest gwarantowane przez konkretny typ używający List.

Posiada również możliwość modyfikacji domyślnej implementacji List na klasie implementującej IList dla say the .Dodaj, .Usunąć Metoda IList daje programiście lot elastyczności i mocy, w przeciwnym razie predefiniowanej przez List

 2
Author: atconway,
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
2010-10-19 15:45:24

Zazwyczaj dobrym podejściem jest użycie IList w publicznym interfejsie API (jeśli jest to właściwe i potrzebna jest semantyka list), a następnie List wewnętrznie, aby zaimplementować API.  Pozwala to na zmianę na inną implementację IList bez łamania kodu używającego twojej klasy.

Lista nazw klas może zostać zmieniona w następnym. NET framework, ale interfejs nigdy się nie zmieni, ponieważ interfejs jest kontraktem.

Zauważ, że jeśli Twoje API będzie używane tylko w pętlach foreach, itd., wtedy może warto rozważyć tylko ujawnienie IEnumerable zamiast.

 0
Author: lazydeveloper,
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
2017-12-01 05:38:20