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?


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)

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();


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,


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.