Lista <T> jest klasą i implementuje zarówno interfejs ICollection <T>, jak i IEnumerable <T> . Ponadto ICollection <T> rozszerza interfejs IEnumerable <T>. Nie są one wymienne, przynajmniej nie ze wszystkich punktów widzenia.
Jeśli masz List <T>, masz gwarancję, że ten obiekt implementuje metody i właściwości wymagane do zaimplementowania przez interfejs ICollection <T> i IEnumerable <T>. Kompilator wie o tym i możesz niejawnie rzutować je „na ICollection <T> lub IEnumerable <T>. Jeśli jednak masz ICollection <T>, musisz najpierw wyraźnie sprawdzić w kodzie, czy jest to List <T>, czy coś innego, być może Słownik <T> (gdzie T to KeyValuePair ) przed rzutowaniem go na to, co pragnienie.
Wiesz, że ICollection rozszerza IEnumerable, więc możesz przerzucić go na IEnumerable. Ale jeśli masz tylko IEnumerable, ponownie nie masz gwarancji, że jest to lista. Być może, ale może być coś innego. Powinieneś spodziewać się niepoprawnego wyjątku rzutowania, jeśli spróbujesz na przykład rzucić Listę <T> na Słownik <T>.
Nie są więc „wymienne”.
Ponadto istnieje wiele ogólnych interfejsów, sprawdź, co można znaleźć w przestrzeni nazw System.Collections.Generic .
Edycja: jeśli chodzi o twój komentarz, absolutnie nie ma ograniczenia wydajności, jeśli używasz List <T> lub jednego z interfejsów, które implementuje. Nadal będziesz musiał utworzyć nowy obiekt, sprawdź następujący kod:
List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;
List , myColl i myEnum wszystkie wskazują na ten sam obiekt. Niezależnie od tego, czy zadeklarujesz go jako List, ICollection, czy IEnumerable, nadal wymagam od programu utworzenia Listy. Mógłbym napisać to:
ICollection<T> myColl = new List<T>();
myColl , w czasie wykonywania jest nadal listą.
Jednakże , to najważniejszy punkt ... aby ograniczyć powstawanie i wzrost konserwacji należy zawsze deklarować zmienne i parametry Metoda z zastosowaniem najniższą możliwą mianownik możliwe dla ciebie, czy jest to interfejs lub abstrakcyjne lub betonu klasy.
Wyobraź sobie, że jedyną rzeczą, której potrzebuje metoda „PerformOperation”, jest wyliczenie elementów, wykonanie pracy i wyjście, w takim przypadku nie potrzebujesz stu dodatkowych metod dostępnych na liście <T>, potrzebujesz tylko tego, co jest dostępne w IEnumerable <T >, więc powinny mieć zastosowanie następujące zasady:
public void PerformOperation(IEnumerable<T> myEnumeration) { ... }
W ten sposób ty i inni programiści wiecie, że dowolny obiekt klasy implementujący interfejs IEnumerable <T> może zostać przekazany tej metodzie. Może to być lista, słownik lub niestandardowa klasa kolekcji, którą napisał inny programista.
Jeśli wręcz przeciwnie, wyraźnie zaznaczysz, że potrzebujesz konkretnej Listy <T> (i chociaż w rzeczywistości tak rzadko się zdarza, może się zdarzyć), Ty i inni programiści wiecie, że musi to być Lista lub inna dziedzicząca klasa z listy.