Навіщо використовувати ICollection, а не IEnumerable або List <T> для відносин багато-багато / один-багато?


359

Я бачу це багато в навчальних посібниках з властивостями навігації як ICollection<T>.

Це обов'язкова вимога до Entity Framework? Чи можу я використовувати IEnumerable?

Яка головна мета використання ICollectionзамість IEnumerableабо навіть List<T>?

Відповіді:


439

Зазвичай те, що ви виберете, залежатиме від того, до яких методів вам потрібно отримати доступ. Загалом - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx ) для списку об'єктів, до яких потрібно лише повторити, ICollection<>(MSDN: http: // msdn.microsoft.com/en-us/library/92t2ye13.aspx ) для переліку об'єктів, які потрібно переробити та змінити, List<>для списку об'єктів, які потрібно переглядати, змінювати, сортувати тощо (див. тут повний список: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx ).

З більш конкретної точки зору, ледаче завантаження підходить для вибору типу. За замовчуванням властивості навігації в Entity Framework оснащені відстеженням змін і є проксі-серверами. Для того, щоб динамічний проксі був створений як властивість навігації, віртуальний тип повинен реалізувати ICollection.

Навігаційна властивість, що представляє кінець відносини "багато", повинна повертати тип, який реалізує ICollection, де T - тип об'єкта на іншому кінці відносини. - Вимоги до створення POCO-проксі MSDN

Детальніше про визначення та управління відносинами MSDN


2
так що з цим Listповинно бути набагато краще, так?
Ян Карло Вірай

3
@JanCarloViray - я, як правило, використовую Listбагато. Хоча він має найвищі витрати, він забезпечує найбільшу функціональність.
Travis J

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

2
Що стосується редагування, обмеження властивості типом інтерфейсу стосується не пам’яті, а інкапсуляції. Поміркуйте: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };використовує ту саму пам'ять, що іprivate List<int> _integers = new List<int> { 1, 2, 3 };
1212

13
@TravisJ: List<T>має GetEnumerator()метод, окремий від його реалізації IEnumerable<T>, який повертає тип змінної структури List<T>.Enumerator. У більшості контекстів цей тип дає дещо кращі показники, ніж окремий об'єкт купи. Компілятори, які використовують перелічувачі типів качок (як це роблять і C # і vb.net), можуть скористатися цим при створенні foreachкоду. Якщо присвоєно List<T>значення " IEnumrable<T>до" foreach, IEnumerable<T>.GetEnumerator()метод поверне об'єкт, виділений з купи, що робить оптимізацію неможливою.
supercat

85

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


3
як щодо порівняння зі списком <T>?
Ян Карло Вірай

12
List<T>знаряддя ICollection<T>.
витрачений

Негенеральний ICollectionне дозволяє будь-яким способом додавати елементи, але він все ще є корисним доповненням, IEnumerable<T>оскільки він забезпечує Countчлена, який, як правило, набагато швидше, ніж перераховувати все. Зауважте, що якщо IList<Cat>або ICollection<Cat>передається код, який очікує IEnumerable<Animal>, Count()метод розширення буде швидким, якщо він реалізує негенеричний ICollection, але не, якщо він реалізує лише загальні інтерфейси, оскільки типовий ICollection<Cat>не буде реалізований ICollection<Animal>.
supercat

58

Відповідаючи на ваше запитання про List<T>:

List<T>- клас; Вказання інтерфейсу дозволяє підвищити гнучкість реалізації. Краще питання - "чому б і ні IList<T>?"

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


21

Є деякі основні відмінності між ICollection та IEnumerable

  • IEnumerable - містить лише метод GetEnumerator для отримання Enumerator і дозволяє циклічно
  • ICollection містить додаткові методи: Додати, видалити, містить, рахувати, CopyTo
  • ICollection успадковується від IEnumerable
  • За допомогою ICollection ви можете змінювати колекцію, використовуючи такі методи, як додавання / видалення. Ви не маєте свободи робити те саме з IEnumerable.

Проста програма:

using System;
using System.Collections;
using System.Collections.Generic;

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Jack", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

13

Я пам’ятаю це таким чином:

  1. IEnumerable має один метод GetEnumerator (), який дозволяє читати значення в колекції, але не записувати в нього. Більшу частину складності використання перелічувача переймає нас кожен оператор у C #. IEnumerable має одну властивість: Current, яка повертає поточний елемент.

  2. ICollection реалізує IEnumerable та додає декілька додаткових властивостей, найвищим використанням яких є Count. Загальна версія ICollection реалізує методи Add () та Remove ().

  3. IList реалізує як IEnumerable, так і ICollection, і додає цілочисельний доступ до індексування елементів (що зазвичай не потрібно, оскільки замовлення виконується в базі даних).


4
Виходячи з того, що ви написали ICollection та IList - те саме. Будь ласка, додайте те, що додано до IList, що не існує в ICollection.
ставки

Інтерфейс ICollection VS IList, єдиний IList в System.Collection, який містить всю функціональність IEnumerable та ICollection та додаткову функціональність. IList має методи Insert and Remove. Обидва методи приймають індекс у своєму параметрі. Отже, він підтримує індексні операції над збиранням.
Е.Мейр

7

Основна ідея використання ICollection- це надання інтерфейсу для доступу лише до читання в кінцевому обсязі даних. Насправді у вас є властивість ICollection.Count . IEnumerableбільше підходить для певного ланцюжка даних, де ви читаєте до певної логічної точки, якась умова, явно визначена споживачем, або до кінця перерахування.


14
TIL, який ICollectionлише для читання, поки ICollection<T>це не так.
Карл Г

2

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

Якщо властивість навігації може містити декілька сутностей (як у відносинах багато-багато-багато або один-до-багатьох), її тип повинен бути списком, в якому записи можна додавати, видаляти та оновлювати, наприклад, ICollection.

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net- mvc-додаток


2

Що я робив у минулому, це оголосити мої колекції внутрішнього класу за допомогою IList<Class>, ICollection<Class>або IEnumerable<Class>(якщо статичний список) залежно від того, чи доведеться мені робити будь-яку кількість наступних методів у моєму сховищі: перерахувати, сортувати / упорядкувати чи змінити . Коли мені просто потрібно перерахувати (і, можливо, сортувати) по об'єктах, тоді я створюю темп List<Class>для роботи з колекцією в методі IEnumerable. Я думаю, що ця практика буде ефективною лише в тому випадку, якщо колекція буде відносно невеликою, але це може бути хорошою практикою в цілому, idk. Будь ласка, виправте мене, якщо є докази того, чому це не було б хорошою практикою.


0

Давайте спробуємо мислити поза коробкою за допомогою логіки та чітко зрозуміти ці три інтерфейси у вашому запитанні:

Коли клас якогось екземпляра реалізує System.Collection.IEnumerable інтерфейс, то простими словами, ми можемо сказати, що цей екземпляр є і численним, і ітерабельним, а це означає, що цей екземпляр дозволяє якось в одному циклі перейти / отримати / пройти / перейти / повторити через / через усі елементи та елементи, які містить цей екземпляр.

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

Кожен клас, який реалізує System.Collection.IEnumerable інтерфейс, також реалізує метод GetEnumerator, який не приймає аргументів і повертає екземпляр System.Collections.IEnumerator.

Примірники інтерфейсу System.Collections.IEnumerator ведуть себе дуже схоже на ітератори C ++.

Коли клас якогось екземпляра реалізує інтерфейс System.Collection.ICollection, простими словами, ми можемо сказати, що цей екземпляр є деякою сукупністю речей.

Універсальна версія цього інтерфейсу, тобто System.Collection.Generic.ICollection, є більш інформативною, оскільки цей загальний інтерфейс прямо вказує, який тип речей у колекції.

Це все розумно, раціонально, логічно і має сенс, що інтерфейс System.Collections.ICollection успадковується від System.Collections.Ізчисленний інтерфейс, тому що теоретично кожна колекція є і численною, і ітерабельною. у кожній колекції.

Інтерфейс System.Collections.ICollection являє собою скінченну динамічну колекцію, яка може змінюватися, а це означає, що існуючі елементи можуть бути вилучені з колекції, а нові елементи можуть бути додані до тієї ж колекції.

Це пояснює, чому інтерфейс System.Collections.ICollection має методи "Додати" та "Видалити".

Оскільки ці екземпляри інтерфейсу System.Collections.ICollection є скінченними колекціями, то слово "скінченне" означає, що кожна колекція цього інтерфейсу завжди має в ньому обмежену кількість елементів та елементів.

Властивість Count System.Collections.ICollection інтерфейс передбачає повернути це число.

System.Collections.IE численний інтерфейс не має цих методів та властивостей, якими володіє інтерфейс System.Collections.ICollection, оскільки це не має сенсу, що System.Collections.IEnumerable буде мати ці методи та властивості, якими володіє інтерфейс System.Collections.ICollection.

Логіка також говорить, що кожен екземпляр, який є і численним, і ітерабельним, не обов'язково є колекцією і не обов'язково мінливим.

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

Якщо я щойно створив якусь кінцеву послідовність простих чисел, наприклад, ця кінцева послідовність простих чисел дійсно є екземпляром System.Collections.IEbroble interface, тому що тепер я можу перейти всі прості числа в цій кінцевій послідовності в один цикл і робити все, що я хочу зробити з кожним із них, як-от друкувати кожне з них у вікно або екран консолі, але ця кінцева послідовність простих чисел не є примірником інтерфейсу System.Collections.ICollection, оскільки це не має сенсу додати складені числа до цієї кінцевої послідовності простих чисел.

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

Крім того, ви, мабуть, хочете використовувати, кодувати та записувати "віддачу прибутковості" у методі GetEnumerator методу System.Collections.IEnumerable для отримання простих чисел і не виділяючи нічого на купі пам'яті, а потім задати збирач сміття (GC) обом. розімкніть та звільніть цю пам’ять з купи, оскільки це, очевидно, і витрата оперативної пам'яті операційної системи, і зниження продуктивності.

Динамічне розподіл пам’яті та розподіл пам’яті на купі повинно здійснюватися під час виклику методів та властивостей інтерфейсу System.Collections.ICollection, але не при виклику методів та властивостей System.Collections.IE незліченного інтерфейсу (хоча System.Collections.IE незліченний інтерфейс має лише 1 метод та 0 властивостей).

Відповідно до сказаного на цій веб-сторінці Stack Overflow, інтерфейс System.Collections.IList просто представляє колекцію, яку можна замовити, і це пояснює, чому методи інтерфейсу System.Collections.IList працюють з індексами на відміну від інтерфейсу System.Collections.ICollection.

Коротше кажучи, інтерфейс System.Collections.ICollection не означає, що його примірник є упорядкованим, але інтерфейс System.Collections.IList це означає.

Теоретично впорядкований набір - це окремий випадок не упорядкованого набору.

Це також має сенс і пояснює, чому інтерфейс System.Collections.IList успадковує інтерфейс System.Collections.ICollection.

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