¿Por qué usar ICollection y no IEnumerable o List <T> en las relaciones de muchos, muchos y uno?

359

Lo veo mucho en tutoriales, con propiedades de navegación como ICollection<T>.

¿Es este un requisito obligatorio para Entity Framework? Puedo usar IEnumerable?

¿Cuál es el propósito principal de usar en ICollectionlugar de IEnumerableo incluso List<T>?

Jan Carlo Viray
fuente

Respuestas:

440

Por lo general, lo que elija dependerá de los métodos a los que necesite acceder. En general: IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx ) para obtener una lista de objetos que solo necesitan iterarse, ICollection<>(MSDN: http: // msdn.microsoft.com/en-us/library/92t2ye13.aspx ) para obtener una lista de objetos que deben iterarse y modificarse, List<>para obtener una lista de objetos que deben iterarse, modificarse, ordenarse, etc. (Ver aquí para obtener una lista completa: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx ).

Desde un punto de vista más específico, la carga diferida entra en juego con la elección del tipo. Por defecto, las propiedades de navegación en Entity Framework vienen con seguimiento de cambios y son proxies. Para que el proxy dinámico se cree como una propiedad de navegación, se debe implementar el tipo virtual ICollection.

Una propiedad de navegación que representa el extremo "muchos" de una relación debe devolver un tipo que implemente ICollection, donde T es el tipo del objeto en el otro extremo de la relación. - Requisitos para crear proxies de POCO MSDN

Más información sobre Definición y gestión de relaciones MSDN

Travis J
fuente
2
entonces, con eso, Listdebería ser mucho mejor, ¿sí?
Jan Carlo Viray
3
@ JanCarloViray: tiendo a usar Listmucho. Aunque tiene la mayor sobrecarga, proporciona la mayor funcionalidad.
Travis J
1
Las listas se definen más por sus indexadores que por la capacidad de ordenarlos (tener un indexador entero facilita la clasificación de algo, pero no es un requisito).
phoog
2
Con respecto a su edición, restringir una propiedad a un tipo de interfaz no se trata de memoria sino de encapsulación. Considere: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };utiliza la misma memoria queprivate List<int> _integers = new List<int> { 1, 2, 3 };
phoog
13
@TravisJ: List<T>tiene un GetEnumerator()método, independiente de su implementación de IEnumerable<T>, que devuelve un tipo de estructura mutable List<T>.Enumerator. En la mayoría de los contextos, ese tipo producirá un rendimiento ligeramente mejor que un objeto de montón independiente. Los compiladores que los enumeradores de tipo pato (como hacen C # y vb.net) pueden aprovechar esto al generar foreachcódigo. Si List<T>se convierte IEnumrable<T>antes de foreach, el IEnumerable<T>.GetEnumerator()método devolverá un objeto asignado en el montón, haciendo imposible la optimización.
supercat
86

ICollection<T>se utiliza porque la IEnumerable<T>interfaz no proporciona forma de agregar elementos, eliminar elementos o modificar la colección.

Justin Niessner
fuente
3
¿Qué hay de comparar con la Lista <T>?
Jan Carlo Viray
12
List<T>implementos ICollection<T>.
gastador
El no genérico ICollectionno permite ninguna forma de agregar elementos, pero sigue siendo un complemento útil IEnumerable<T>porque proporciona un Countmiembro que generalmente es mucho más rápido que enumerar todo. Tenga en cuenta que si se pasa una IList<Cat>o ICollection<Cat>al código que espera una IEnumerable<Animal>, el Count()método de extensión será rápido si implementa lo no genérico ICollection, pero no si solo implementa las interfaces genéricas, ya que una típica ICollection<Cat>no se implementará ICollection<Animal>.
supercat
58

Respondiendo a su pregunta sobre List<T>:

List<T>es una clase especificar una interfaz permite una mayor flexibilidad de implementación. Una mejor pregunta es "¿por qué no IList<T>?"

Para responder a esa pregunta, considere lo que se IList<T>agrega a ICollection<T>: indexación de enteros, lo que significa que los elementos tienen un orden arbitrario y se pueden recuperar por referencia a ese orden. Esto probablemente no sea significativo en la mayoría de los casos, ya que los artículos probablemente deban ordenarse de manera diferente en diferentes contextos.

phoog
fuente
21

Hay algunas diferencias básicas entre ICollection e IEnumerable

  • IEnumerable : contiene solo el método GetEnumerator para obtener Enumerator y permite el bucle
  • ICollection contiene métodos adicionales: Agregar, Eliminar, Contiene, Contar, CopyTo
  • ICollection se hereda de IEnumerable
  • Con ICollection puede modificar la colección mediante el uso de métodos como agregar / quitar. No tienes la libertad de hacer lo mismo con IEnumerable.

Programa simple:

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;
        }
    }
}
Ramakrishnan
fuente
13

Lo recuerdo así:

  1. IEnumerable tiene un método GetEnumerator () que permite leer los valores de una colección pero no escribir en ellos. La mayor parte de la complejidad del uso del enumerador es tratada por nosotros para cada enunciado en C #. IEnumerable tiene una propiedad: Current, que devuelve el elemento actual.

  2. ICollection implementa IEnumerable y agrega algunas propiedades adicionales, la mayoría de las cuales es Count. La versión genérica de ICollection implementa los métodos Add () y Remove ().

  3. IList implementa tanto IEnumerable como ICollection, y agrega el acceso de indexación de enteros a los elementos (que generalmente no es necesario, ya que el pedido se realiza en la base de datos).

usuario3918295
fuente
44
Según lo que escribiste, ICollection e IList son lo mismo. Agregue lo que se agrega a IList que no existe en ICollection.
apuestas
ICollection VS IList, interfaz IList-only en el System.Collection que contiene toda la funcionalidad de IEnumerable e ICollection y funcionalidad adicional. IList tiene métodos de Insertar y Eliminar. Ambos métodos aceptan el índice en su parámetro. Por lo tanto, admite operaciones basadas en índices sobre la recopilación.
E.Meir
7

La idea básica de usar ICollectiones proporcionar una interfaz para acceso de solo lectura a una cantidad finita de datos. De hecho, tiene una propiedad ICollection.Count . IEnumerablees más adecuado para alguna cadena de datos donde se lee hasta algún punto lógico, alguna condición especificada de forma explícita por el consumidor o hasta el final de la enumeración.

Tigran
fuente
14
TIL que ICollectiones de solo lectura mientras ICollection<T>que no lo es.
Carl G
2

Las propiedades de navegación generalmente se definen como virtuales para que puedan aprovechar ciertas funciones de Entity Framework, como la carga diferida.

Si una propiedad de navegación puede contener varias entidades (como en relaciones de varios a varios o de uno a varios), su tipo debe ser una lista en la que se pueden agregar, eliminar y actualizar entradas, como 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- aplicación mvc

LewisAntonio803
fuente
2

Lo que he hecho en el pasado es declarar mis colecciones de clases internas usando IList<Class>, ICollection<Class>o IEnumerable<Class>(si es una lista estática) dependiendo de si tendré que hacer cualquier cantidad de lo siguiente en un método en mi repositorio: enumerar, ordenar / ordenar o modificar . Cuando solo necesito enumerar (y tal vez ordenar) sobre objetos, entonces creo un temporal List<Class>para trabajar con la colección dentro de un método IEnumerable. Creo que esta práctica solo sería efectiva si la colección es relativamente pequeña, pero puede ser una buena práctica en general, idk. Corríjame si hay evidencia de por qué esto no sería una buena práctica.

yardpenalty.com
fuente
0

Tratemos de pensar fuera de la caja con / por lógica y comprenda claramente estas tres interfaces en su pregunta:

Cuando la clase de alguna instancia implementa la interfaz System.Collection.IEnumerable, entonces, en palabras simples, podemos decir que esta instancia es enumerable e iterable, lo que significa que esta instancia permite de alguna manera en un solo ciclo ir / obtener / pasar / recorrer / iterar sobre / a través de todos los elementos y elementos que contiene esta instancia.

Esto significa que también es posible enumerar todos los elementos y elementos que contiene esta instancia.

Cada clase que implementa la interfaz System.Collection.IEnumerable también implementa el método GetEnumerator que no toma argumentos y devuelve una instancia de System.Collections.IEnumerator.

Las instancias de la interfaz System.Collections.IEnumerator se comportan de manera muy similar a los iteradores de C ++.

Cuando la clase de alguna instancia implementa la interfaz System.Collection.ICollection, en palabras simples, podemos decir que esta instancia es una colección de cosas.

La versión genérica de esta interfaz, es decir, System.Collection.Generic.ICollection, es más informativa porque esta interfaz genérica establece explícitamente cuál es el tipo de elementos de la colección.

Todo esto es razonable, racional, lógico y tiene sentido que la interfaz System.Collections.ICollection herede de System.Collections.IEnumerable interfaz, porque teóricamente cada colección también es enumerable e iterable y esto es teóricamente posible revisar todos los elementos y elementos. en cada colección

La interfaz System.Collections.ICollection representa una colección dinámica finita que se puede cambiar, lo que significa que los elementos existentes se pueden eliminar de la colección y se pueden agregar nuevos elementos a la misma colección.

Esto explica por qué la interfaz System.Collections.ICollection tiene los métodos "Agregar" y "Eliminar".

Debido a que las instancias de la interfaz System.Collections.ICollection son colecciones finitas, la palabra "finito" implica que cada colección de esta interfaz siempre tiene un número finito de elementos y elementos.

La propiedad Cuenta de la interfaz System.Collections.ICollection supone devolver este número.

La interfaz System.Collections.IEnumerable no tiene estos métodos y propiedades que tiene la interfaz System.Collections.ICollection, porque no tiene ningún sentido que System.Collections.IEnumerable tenga estos métodos y propiedades que la interfaz System.Collections.ICollection tiene.

La lógica también dice que cada instancia que es enumerable e iterable no es necesariamente una colección y no necesariamente modificable.

Cuando digo cambiable, quiero decir que no piense de inmediato que puede agregar o eliminar algo de algo que es enumerable e iterable.

Si acabo de crear una secuencia finita de números primos, por ejemplo, esta secuencia finita de números primos es de hecho una instancia de System.Collections.IEnumerable interface, porque ahora puedo repasar todos los números primos en esta secuencia finita en un solo bucle y hacer lo que quiera hacer con cada uno de ellos, como imprimir cada uno de ellos en la ventana o pantalla de la consola, pero esta secuencia finita de números primos no es una instancia de la interfaz System.Collections.ICollection, porque esto no tiene sentido para agregue números compuestos a esta secuencia finita de números primos.

También desea en la próxima iteración obtener el siguiente número primo más cercano al número primo actual en la iteración actual, si es así, tampoco desea eliminar los números primos existentes de esta secuencia finita de números primos.

También es probable que desee usar, codificar y escribir "rendimiento de rendimiento" en el método GetEnumerator de la interfaz System.Collections.IEnumerable para producir los números primos y no asignar nada en el montón de memoria y luego asignar el recolector de basura (GC) a ambos desasignar y liberar esta memoria del montón, porque esto es obviamente un desperdicio de memoria del sistema operativo y disminuye el rendimiento.

La asignación de memoria dinámica y la desasignación en el montón se deben realizar al invocar los métodos y propiedades de la interfaz System.Collections.ICollection, pero no al invocar los métodos y propiedades de System.Collections.IEnumerable interfaz (aunque System.Collections.IEnumerable interface solo tiene 1 método y 0 propiedades).

Según lo que otros dijeron en esta página web de desbordamiento de pila, la interfaz System.Collections.IList simplemente representa una colección ordenable y esto explica por qué los métodos de la interfaz System.Collections.IList funcionan con índices en contraste con los de la interfaz System.Collections.ICollection.

En resumen, la interfaz System.Collections.ICollection no implica que una instancia de la misma sea ordenable, pero la interfaz System.Collections.IList sí lo implica.

El conjunto teóricamente ordenado es un caso especial de conjunto no ordenado.

Esto también tiene sentido y explica por qué la interfaz System.Collections.IList hereda la interfaz System.Collections.ICollection.

usuario11336341
fuente