Разница между различными интерфейсами коллекции Generic в C #

11

Я играю с C # для Windows и ASP.net MVC в течение некоторого времени. Но я все еще неясен в некоторых областях. Я пытаюсь понять основное различие между проблемами производительности и использованием и обменом подобными видами интерфейсов универсальных коллекций .

Какова основная разница между IEnumerable<T>, ICollection<T>, List<T>(Class)?

Я, кажется, использую и обмениваю их, не видя проблем в моих приложениях. Кроме того, есть ли еще подобные общие коллекции, подобные этим, которые можно заменить этими тремя?

Панкадж Упадхяй
источник
2
также есть IList <T>
jk.

Ответы:

19

List <T> является классом и реализует интерфейсы ICollection <T> и IEnumerable <T> . Кроме того, ICollection <T> расширяет интерфейс IEnumerable <T>. Они не являются взаимозаменяемыми, по крайней мере, не со всех точек зрения.

Если у вас есть List <T>, вы гарантируете, что этот объект реализует методы и свойства, необходимые для реализации интерфейсами ICollection <T> и IEnumerable <T>. Компилятор знает это, и вам разрешено приводить их «вниз» либо к ICollection <T>, либо к IEnumerable <T> неявно. Однако, если у вас есть ICollection <T>, вы должны сначала явно проверить в своем коде, является ли это List <T> или что-то еще, возможно, Dictionary <T> (где T - KeyValuePair ), прежде чем привести его к тому, что вы желание.

Вы знаете, что ICollection расширяет IEnumerable, поэтому вы можете преобразовать его в IEnumerable. Но если у вас есть только IEnumerable, опять же вам не гарантируется, что это список. Может быть, но это может быть что-то еще. Следует ожидать недопустимого исключения приведения, если вы попытаетесь привести, например, List <T> к словарю <T>.

Таким образом, они не являются «взаимозаменяемыми».

Кроме того, существует множество универсальных интерфейсов, посмотрите, что вы можете найти в пространстве имен System.Collections.Generic .

Отредактируйте: в отношении вашего комментария нет абсолютно никакого снижения производительности, если вы используете List <T> или один из интерфейсов, которые он реализует. Вам все еще нужно будет создать новый объект, посмотрите следующий код:

List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;

list , myColl и myEnum указывают на один и тот же объект. Независимо от того, объявляете ли вы его как List, ICollection или IEnumerable, я все еще требую, чтобы программа создала List. Я мог бы написать это:

ICollection<T> myColl = new List<T>();

myColl , во время выполнения все еще список.

Тем не менее , это самый важный момент ... чтобы уменьшить связь и повысить удобство сопровождения, вы всегда должны объявлять свои переменные и параметры метода, используя наименьший возможный для вас знаменатель, будь то интерфейс, абстрактный или конкретный класс.

Представьте, что единственное, что нужно методу «PerformOperation», это перечислить элементы, выполнить некоторую работу и выйти, в этом случае вам не нужно больше сотни методов, доступных в List <T>, вам нужно только то, что доступно в IEnumerable <T >, поэтому должно применяться следующее:

public void PerformOperation(IEnumerable<T> myEnumeration) { ... }

Делая это, вы и другие разработчики знаете, что этот метод может быть передан любому объекту класса, реализующего интерфейс IEnumerable <T>. Это может быть List, Dictionary или пользовательский класс коллекции, написанный другим разработчиком.

Если, наоборот, вы указываете, что вам явно нужен конкретный List <T> (и хотя в реальной жизни это редко бывает, это все же может произойти), вы и другие разработчики знаете, что это должен быть либо List, либо другой конкретный класс, наследующий из списка.

Jalayn
источник
Прежде всего, спасибо. Теперь проблема в том, как решить, какой использовать ?? Поскольку List <T> реализует оба интерфейса, почему бы не всегда использовать его в каждом месте, где требуется IEnumerable или ICollection. Будет ли использование списка всегда влиять на производительность? Пожалуйста, отредактируйте свой ответ, чтобы ответить на эти вопросы
Pankaj Upadhyay
Я отредактировал ответить на ваши вопросы производительности
Jalayn
+1, но я бы добавил, что в тех редких случаях, когда вам действительно нужно передать список методу, вы должны использовать его, IListа не Listв объявлении метода.
Konamiman
@Konamiman - Зависит, если вам нужна List<>определенная функциональность, например .AddRange(). Это IList<>не разоблачает это.
Бобсон
6

Взгляните на страницы MSDN для ICollection и IEnumerable .

В очень абстрактных терминах я так думаю об этих типах.

IEnumerable - это все, что может быть перечислено, то есть повторено. Это не обязательно означает «коллекцию»; например, IQueryable реализует IEnumerable, и это не коллекция, а то, что может быть запрошено для возврата объектов. Для реализации IEnumerable объект должен иметь возможность возвращать объект только при запросе. Я мог бы сказать, что у меня есть множество задач, которые я собираюсь выполнить сегодня (это не список, потому что я не записал и не сформулировал его, но я мог бы сказать вам, что я собираюсь сделать сейчас, и если бы вы спросили «а потом?», я бы смог рассказать вам следующее задание).

ICollection более конкретна, чем IEnumerable. Ключевое отличие состоит в том, что Коллекция знает, сколько предметов она содержит; чтобы определить, сколько элементов в Enumerable, вы эффективно просматриваете и подсчитываете их:

Я: Ребята, сколько предметов у вас в каждом есть?

Перечислимый: я действительно не знаю. Ну, вот один пункт. У меня есть еще один, так что это два. И еще один, так что это три ... и еще один ... хорошо, так что это 2382. Больше никаких предметов, так что у меня есть 2382. Не спрашивайте меня снова, потому что мне придется снова пройти их все.

Коллекция: у меня 2382 предмета. Я уже знаю, что.

Как правило, коллекция - это то, что уже знает, где находятся все ее элементы, и ей не нужно будет искать и генерировать их, когда вы их запрашиваете. Это больше ... бетон, чем перечисляемый.

На мой взгляд, разница между перечисляемым и коллекцией намного больше, чем разница между коллекцией и списком. На самом деле, я изо всех сил пытаюсь придумать практическую разницу между коллекцией и списком, но я считаю, что список предоставляет лучшие методы для поиска и упорядочения.

Другие виды коллекций включают в себя Queueи Stack, а также Dictionary.

Имена этих типов весьма полезны - вы можете представить очередь и стек в качестве их реальных аналогов и рассмотреть различия, которые могут у вас быть в списке.

Кирк Бродхерст
источник
«Я изо всех сил пытаюсь придумать практическую разницу между коллекцией и списком» ... Позже в своем ответе вы сами отвечаете на это. ListЭто ICollection, но ICollectionне всегда List( Queue, Stack, Dictionary...)
Стивен Jeuris
@ Стивен Это очень бессвязный ответ. Я согласен, что это важное различие, но я бы не назвал это практическим различием. Что это значит для пользователя?
Кирк Бродхерст
Это легко! :) Queue<int> queue = (Queue<int>)list;брошу InvalidCastExceptionкогда listне открывается Queue<int>. Разница между очередью и списком выходит за рамки этого вопроса.
Стивен Джеурис
Не является критическим аспектом IEnumerable, что он может возвращать текущий и следующий элементы - вы как бы намекаете на это, но прямо не говорите об этом. По сути, то, что реализует один только IEnumerable, не может вернуть произвольный элемент своих членов при запросе - только текущий и следующий.
Кори
@cori Это очень лаконичный способ выразить это, намного яснее, чем мой ответ.
Кирк Бродхерст
-1

IQueryable:

запрос не выполняется до тех пор, пока он действительно не перебирает элементы, возможно, с помощью .ToList ()

IEnumerable:

форвардный список предметов. Вы не можете получить "пункт 4", не пройдя пункты 0-3. список только для чтения, вы не можете добавить или удалить из него. Все еще может использовать отложенное выполнение.

IList:

произвольный доступ к полному списку полностью в памяти поддерживает добавление и удаление

ICollection:

Находится между IEnumerable и IList. Что «лучше» зависит от ваших требований. Обычно, хотя IEnumerable «достаточно хорош», если вы хотите отображать только элементы. По крайней мере, всегда используйте общий вариант.

Зия Каммар
источник
этот ответ, кажется, не добавляет ничего ценного по сравнению с тем, что уже было опубликовано в предыдущих ответах
комнат
это всего лишь простая концепция обо всем
Зия Каммар