Зачем использовать ICollection, а не IEnumerable или List <T> для отношений многие-многие / один-многие?


359

Я часто вижу это в уроках со свойствами навигации как ICollection<T>.

Это обязательное требование для Entity Framework? Могу ли я использоватьIEnumerable ?

Какова основная цель использования ICollectionвместо IEnumerableили даже List<T>?

Ответы:


440

Обычно выбор зависит от того, к каким методам вам нужен доступ. В общем случае - 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. Хотя у него больше всего накладных расходов, он обеспечивает большую функциональность.
Трэвис Дж

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

2
Что касается вашего редактирования, то ограничение свойства типом интерфейса относится не к памяти, а к инкапсуляции. Рассмотрим: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };использует ту же память, что иprivate List<int> _integers = new List<int> { 1, 2, 3 };
phoog

13
@TravisJ: List<T>имеет GetEnumerator()метод, отдельный от его реализации IEnumerable<T>, который возвращает изменяемый тип структуры List<T>.Enumerator. В большинстве случаев этот тип даст немного лучшую производительность, чем автономный объект кучи. Компиляторы, которые используют перечислители утилитарного типа (как это делают и C #, и vb.net), могут воспользоваться этим при генерации foreachкода. Если метод List<T>приведен к IEnumrable<T>перед foreach, IEnumerable<T>.GetEnumerator()метод вернет объект, выделенный в куче , что сделает оптимизацию невозможной.
суперкат

86

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>.
суперкат

58

Отвечая на ваш вопрос о List<T>:

List<T>это класс; указание интерфейса обеспечивает большую гибкость реализации. Лучший вопрос - почему бы и нет IList<T>?

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


21

Есть некоторые основные различия между ICollection и IEnumerable

  • IEnumerable - содержит только метод GetEnumerator для получения Enumerator и позволяет выполнять циклы
  • ICollection содержит дополнительные методы: Add, Remove, Contains, Count, 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 и 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. Я думаю, что эта практика будет эффективной только в том случае, если коллекция будет относительно небольшой, но в целом это может быть хорошей практикой, ИДК. Пожалуйста, поправьте меня, если есть доказательства того, почему это не будет хорошей практикой.


0

Давайте попробуем мыслить нестандартно с помощью / by логики и четко понимать эти три интерфейса в вашем вопросе:

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

Это означает, что также возможно перечислить все элементы и элементы, которые содержит этот экземпляр.

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

Экземпляры интерфейса System.Collections.IEnumerator ведут себя очень похоже на итераторы C ++.

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

Универсальная версия этого интерфейса, то есть System.Collection.Generic.ICollection, является более информативной, поскольку этот универсальный интерфейс явно указывает тип объектов в коллекции.

Все это разумно, рационально, логично и имеет смысл, что интерфейс System.Collections.ICollection наследуется от интерфейса System.Collections.IEnumerable, поскольку теоретически каждая коллекция также является и перечислимой, и итеративной, и теоретически можно обойти все элементы и элементы. в каждой коллекции.

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

Это объясняет, почему интерфейс System.Collections.ICollection имеет методы «Добавить» и «Удалить».

Поскольку экземпляры интерфейса System.Collections.ICollection являются конечными коллекциями, то слово «конечный» подразумевает, что каждая коллекция этого интерфейса всегда имеет конечное число элементов и элементов.

Свойство Count интерфейса System.Collections.ICollection предполагает возвращение этого числа.

Интерфейс System.Collections.IEnumerable не имеет этих методов и свойств, которые есть у интерфейса System.Collections.ICollection, поскольку он не имеет никакого смысла в том, что System.Collections.IEnumerable будет иметь эти методы и свойства, которые есть в интерфейсе System.Collections.ICollection.

Логика также гласит, что каждый перечисляемый и итеративный экземпляр не обязательно является коллекцией и не обязательно изменяем.

Когда я говорю «изменяемый», я имею в виду, что не следует сразу думать, что вы можете добавить или удалить что-то из того, что является и перечислимым, и итеративным.

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

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

Также вы, вероятно, захотите использовать, кодировать и записывать «возвращение дохода» в методе GetEnumerator интерфейса System.Collections.IEnumerable, чтобы получить простые числа и ничего не распределять в куче памяти, а затем назначить сборщик мусора (GC) обоим освободите и освободите эту память из кучи, поскольку это, очевидно, одновременно приводит к потере памяти операционной системы и снижает производительность.

Динамическое выделение и освобождение памяти в куче должно выполняться при вызове методов и свойств интерфейса System.Collections.ICollection, но не при вызове методов и свойств интерфейса System.Collections.IEnumerable (хотя интерфейс System.Collections.IEnumerable имеет только 1 метод и 0 свойств).

Согласно тому, что другие говорили на этой веб-странице переполнения стека, интерфейс 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.