Різниця між різними інтерфейсами колекції в C #


11

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

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

Я, здається, використовую їх і обмінююся ними, не бачачи жодних проблем у своїх програмах. Також, чи є ще подібні родові колекції на кшталт цих, які можна обміняти цими трьома?


2
є також IList <T> а
jk.

Відповіді:


19

Список <T> - клас і реалізує інтерфейси ICollection <T> та IEnumerable <T> . Крім того, ICollection <T> розширює інтерфейс IEnumerable <T>. Вони не взаємозамінні, принаймні, не з усіх точок зору.

Якщо у вас є Список <T>, вам гарантується, що цей об’єкт реалізує методи та властивості, необхідні для реалізації інтерфейсом ICollection <T> та IEnumerable <T>. Компілятор це знає, і вам дозволяється неявно відкидати їх на ICollection <T> або IEnumerable <T>. Однак якщо у вас є ICollection <T>, ви повинні спочатку чітко перевірити у своєму коді, чи це список <T> чи щось інше, можливо, словник <T> (де T - це KeyValuePair ) перед тим, як надати його на те, що ви бажання.

Ви знаєте, що ICollection розширює IEnumerable, тому ви можете скинути його на IEnumerable. Але якщо у вас є лише IEnumerable, знову ж таки вам не гарантується, що це список. Це може бути, але це може бути щось інше. Ви можете очікувати недійсного винятку при видачі, якщо ви намагаєтесь, наприклад, передати список <T> до словника <T>.

Тож вони не є "взаємозамінними".

Також існує багато загальних інтерфейсів, ознайомтеся з тим, що ви можете знайти в просторі імен System.Collections.Generic .

Редагувати: стосовно вашого коментаря, штраф за ефективність абсолютно не застосовується, якщо ви використовуєте Список <T> або один із інтерфейсів, які він реалізує. Вам все одно знадобиться створити новий об’єкт, перегляньте наступний код:

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

list , myColl і myEnum всі вказують на один і той же об'єкт. Незалежно від того, декларуєте ви це як Список, ICollection або IEnumerable, я все ще вимагаю, щоб програма створила список. Я міг би написати це:

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

myColl , під час виконання все ще є списком.

Однак це найважливіший момент ... щоб зменшити зв’язок та збільшити ремонтопридатність, завжди слід оголошувати свої змінні та параметри методу, використовуючи найменший можливий для вас знаменник, будь то інтерфейс чи абстрактний чи конкретний клас.

Уявіть, що єдине, що потрібно методу "PerformOperation" - це перерахувати елементи, виконати певну роботу та вийти, у цьому випадку вам не потрібно ще сто методів, доступних у Список <T>, вам потрібно лише те, що доступне в IEnumerable <T >, тож слід застосувати наступне:

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

Роблячи це, ви та інші розробники знаєте, що цьому методу може бути наданий будь-який об’єкт класу, що реалізує інтерфейс IEnumerable <T>. Це може бути список, словник або спеціальний клас колекції, який написав інший розробник.

Якщо навпаки, ви вказуєте, що вам явно потрібен конкретний список <T> (і хоча це в реальному житті рідко трапляється), ви та інші розробники знаєте, що це повинен бути або Список, або інший конкретний клас, що успадковує зі списку.


Перш за все дякую. Тепер питання викликає занепокоєння, як вирішити, що використовувати ?? Оскільки List <T> реалізує обидва інтерфейси, чому б не завжди використовувати його в кожному місці, де потрібні IEnumerable або ICollection. Чи завжди список, що має список, матиме ефективність? Будь ласка, відредагуйте свою відповідь, щоб відповісти на ці проблеми
Панкай Упадхей

Я відредагував відповіді на ваші запитання щодо продуктивності
Jalayn

+1, але я хотів би додати, що у рідкісних випадках, коли вам потрібно передати список методу, вам слід скористатися, IListа не Listв декларації методу.
Конаміман

@Konamiman - залежить від того, чи потрібна вам List<>певна функціональність, наприклад .AddRange(). Це IList<>не викриває цього.
Бобсон

6

Перегляньте сторінки MSDN для ICollection та IEnumerable .

В дуже абстрактному плані саме так я розумію ці типи.

IEnumerable - це все, що можна перерахувати - тобто повторити його. Це не обов'язково означає "колекцію"; наприклад, IQueryable реалізує IEnumerable, і це не колекція, але це те, що можна запитати для повернення об'єктів. Для реалізації IEnumerable об'єкт потрібно лише мати змогу повернути об'єкт при запиті. Я можу сказати, що у мене є безліч завдань, які я буду робити сьогодні (це не список, тому що я його не записав і не сформулював, але я міг би сказати вам, що я зараз буду робити, і якщо ви запитали "а потім?", я зможу сказати вам наступне завдання).

ICollection є більш конкретним, ніж IEnumerable. Ключова відмінність полягає в тому, що колекція знає, скільки предметів вона містить; щоб випрацювати, скільки предметів міститься в безлічі, ви ефективно перебираєте їх і рахуєте їх:

Я: Хлопці, скільки предметів у вас є?

Численні: Я насправді не знаю. Ну ось один пункт. У мене є ще один, тож це два. І ще один, тож це три ... і ще один ... нормально, так це 2382. Більше предметів немає, тому у мене 2382. Не запитуй мене знову, бо мені доведеться переглядати їх ще раз.

Колекція: У мене 2382 позиції. Я це вже знаю.

Колекція, як правило, вже знає, де знаходяться всі її елементи, і не потрібно їх шукати або генерувати, коли ви просите їх. Це більше ... конкретний, ніж численні.

На мій погляд, різниця між Колекцією та Колекцією набагато більша, ніж різниця між Збіркою та Списком. Насправді я намагаюся думати про практичну різницю між колекцією та списком, але я вважаю, що Список пропонує кращі методи пошуку та замовлення.

Інші типи колекцій включають Queueі Stack, а також Dictionary.

Назви цих типів є досить корисними - ви можете уявити чергу та стек як їх аналоги в реальному світі та врахувати відмінності, які можуть виникнути у списку.


"Я намагаюся придумати практичну різницю між збіркою та списком" ... Пізніше у своїй відповіді ви самі на це відповідаєте. ListЦе ICollection, але ICollectionне завжди List( Queue, Stack, Dictionary...)
Стівен Jeuris

@Steven Це дуже бурхлива відповідь. Я погоджуюся, що це важлива різниця, але я б не називав це практичною різницею. Що це означає для користувача?
Кірк Бродхерст

Це легко! :) Queue<int> queue = (Queue<int>)list;кину, InvalidCastExceptionколи listне є Queue<int>. Різниця між чергою та списком виходить за рамки цього питання.
Стівен Євріс

Чи не найважливіший аспект IEnumerable, що він може повернути поточний та наступний елементи - ви начебто натякаєте на це, але прямо не говоріть про це. По суті, те, що реалізує IEnumerable поодинці, не може повернути довільний елемент своїх членів при запиті - лише поточний та наступний.
cori

@cori Це дуже лаконічний спосіб висловити це, набагато чіткіше моєї відповіді.
Кірк Бродхерст

-1

IQueyable:

запит не виконується до тих пір, поки дійсно не повториться над елементами, можливо, виконавши .ToList ()

Численні:

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

ІЛІСТ:

випадковий доступ до повного списку повністю в пам'яті підтримує додавання та видалення

ICollection:

Знаходиться між IEnumerable та IList. Що "найкраще", залежить від ваших вимог. Зазвичай IEnumerable є "досить хорошим", якщо ви хочете відображати лише елементи. Принаймні завжди використовуйте загальний варіант.


ця відповідь, здається, не додає нічого цінного над тим, що вже було опубліковано в попередніх відповідях
гнат

це просто просте поняття про все
Zia Qammar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.