No se puede convertir de un IEnumerable <T> a un ICollection <T>

91

He definido lo siguiente:

public ICollection<Item> Items { get; set; }

Cuando ejecuto este código:

Items = _item.Get("001");

Recibo el siguiente mensaje:

Error   3   
Cannot implicitly convert type 
'System.Collections.Generic.IEnumerable<Storage.Models.Item>' to 
'System.Collections.Generic.ICollection<Storage.Models.Item>'. 
An explicit conversion exists (are you missing a cast?)

¿Alguien puede explicar qué estoy haciendo mal? Estoy muy confundido acerca de la diferencia entre Enumerable, Colecciones y el uso de ToList ()

Información agregada

Más adelante en mi código tengo lo siguiente:

for (var index = 0; index < Items.Count(); index++) 

¿Estaría bien para definir Items como IEnumerable?

Samantha JT Star
fuente
3
¿Puede proporcionar más información sobre el tipo de _item y la firma de Get (string) (específicamente el tipo de retorno)?
Dr. Andrew Burnett-Thompson
¿Por qué no cambiar el tipo así? public IEnumerable<Item> Items { get; set; }¿Tienes alguna razón especial para tenerlo así ICollection?
Shadow Wizard es Ear For You
IEnumerable <T> Get (string pk);
Samantha JT Star

Respuestas:

113

ICollection<T>hereda de IEnumerable<T>so para asignar el resultado de

IEnumerable<T> Get(string pk)

a un ICollection<T>hay dos formas.

// 1. You know that the referenced object implements `ICollection<T>`,
//    so you can use a cast
ICollection<T> c = (ICollection<T>)Get("pk");

// 2. The returned object can be any `IEnumerable<T>`, so you need to 
//    enumerate it and put it into something implementing `ICollection<T>`. 
//    The easiest is to use `ToList()`:
ICollection<T> c = Get("pk").ToList();

La segunda opción es más flexible, pero tiene un impacto en el rendimiento mucho mayor. Otra opción es almacenar el resultado como un a IEnumerable<T>menos que necesite la funcionalidad adicional agregada por la ICollection<T>interfaz.

Comentario de rendimiento adicional

El bucle que tienes

for (var index = 0; index < Items.Count(); index++)

funciona en un IEnumerable<T>pero es ineficiente; cada llamada a Count()requiere una enumeración completa de todos los elementos. Utilice una colección y la Countpropiedad (sin paréntesis) o conviértala en un bucle foreach:

foreach(var item in Items)
Anders Abel
fuente
1
¿Cuál es la funcionalidad adicional agregada por ICollection?
Samantha JT Star
7
ICollection<T>se puede manipular (consulte el documento para obtener más detalles), mientras que un IEnumerable<T>solo se puede enumerar.
Anders Abel
Necesito tener algo donde pueda ejecutar diferentes consultas LINQ. No necesito agregar ni hacer nada parecido a la lista. ¿Eso significa que estaría mejor con ICollection?
Samantha JT Star
LINQ funciona IEnumerable<T>así que IEnumerable<T>es suficiente en ese caso.
Anders Abel
31

No puede convertir directamente de IEnumerable<T>a ICollection<T>. Puede usar el ToListmétodo de IEnumerable<T>para convertirlo aICollection<T>

someICollection = SomeIEnumerable.ToList();

Haris Hasan
fuente
Esto funciona para mi. Pero, ¿es una buena idea para mí convertir o sería mejor usar IEnumerable como el tipo de Items. Si uso IEnumerable, ¿lo estoy haciendo para poder realizar más acciones en los elementos si es necesario más adelante en mi programa?
Samantha JT Star
ICollection ya implementa IEnumerable. Si le preocupan las acciones disponibles, creo que debería optar por ICollection. Es mejor si puede leer la diferencia real entre los dos y luego decidir qué desea usar realmente
Haris Hasan
Estoy tratando de entender qué ventajas tendría si usara ToList (). Una vez que tenga los datos, me gustaría ejecutar consultas LINQ contra Items.
Samantha JT Star
ToList () funcionará, pero como ha indicado en sus comentarios, Get () devuelve una ICollection, por lo que realmente solo necesita hacer una conversión a ICollection <T>, o mejor aún, cambiar la firma de retorno de Get a ICollection <T> . Usar ToList o ToArray funcionará, pero también incurrirá en una operación innecesaria de creación de memoria / copia
Dr. Andrew Burnett-Thompson
Puede ejecutar consultas LINQ en IEnumerable e ICollection. Ventajas ... una que sé en este momento es que Count ICollection mantiene el recuento y IEnumerable devuelve el resultado al calcular cuántos elementos tiene. ICollection proporciona un método de eliminación adicional que Ienumerables no ofrece
Haris Hasan
1

Pendiente más información sobre la pregunta:

proporcione más información sobre el tipo de artículo y la firma de Get

Dos cosas que puedes probar son:

  • Para convertir el valor de retorno de _item.Get to (ICollection)
  • en segundo lugar, use _item.Get ("001"). ToArray () o _item.Get ("001"). ToList ()

Tenga en cuenta que el segundo tendrá un impacto en el rendimiento de la copia de la matriz. Si la firma (tipo de retorno) de Get no es una ICollection, la primera no funcionará, si no es IEnumerable, la segunda no funcionará.


Después de su aclaración a la pregunta y en los comentarios, personalmente declararía el tipo de devolución de _item.Get ("001") a ICollection. Esto significa que no tendrá que realizar ninguna conversión o conversión (a través de ToList / ToArray), lo que implicaría una operación innecesaria de creación / copia.

// Leave this the same
public ICollection<Item> Items { get; set; }

// Change function signature here:
// As you mention Item uses the same underlying type, just return an ICollection<T>
public ICollection<Item> Get(string value); 

// Ideally here you want to call .Count on the collectoin, not .Count() on 
// IEnumerable, as this will result in a new Enumerator being created 
// per loop iteration
for (var index = 0; index < Items.Count(); index++) 

Atentamente,

Dr. Andrew Burnett-Thompson
fuente
1
La firma es: IEnumerable <T> Get (string pk); Los artículos se utilizan para guardar los registros de artículos que se devuelven. Más adelante, los repito para crear un informe. Estaría bien para usar cualquier cosa que funcione. ¿Cuál crees que sería el mejor tipo de tipo de datos?
Samantha JT Star
1
Sugeriría cambiar el tipo de datos de Items a IEnumerable <T> para que coincida con Get, o cambiar el tipo de retorno de Get a ICollection <T> para que coincida con Items. ¿Supongo que estos dos son el mismo tipo subyacente simplemente declarado de manera diferente? SI son del mismo tipo, desea evitar el uso de ToList () o ToArray (), ya que realiza una asignación de memoria y una copia de matriz innecesarias. Si no son del mismo tipo, debe realizar una conversión
Dr. Andrew Burnett-Thompson
Agregué a la pregunta para mostrar dónde usaré los elementos más tarde. Tiene razón cuando dice el mismo tipo subyacente.
Samantha JT Star
Ok, entonces simplemente cambiaría el tipo de retorno de Get, ya que entonces no necesita hacer ninguna conversión (a través de ToList / ToArray, que es lento), o conversión. Espero que esto ayude :)
Dr. Andrew Burnett-Thompson