Impossibile convertire da IEnumerable <T> a ICollection <T>


94

Ho definito quanto segue:

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

Quando eseguo questo codice:

Items = _item.Get("001");

Ricevo il seguente messaggio:

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?)

Qualcuno può spiegare cosa sto facendo di sbagliato. Sono molto confuso sulla differenza tra Enumerable, Collections e usando ToList ()

Informazioni aggiunte

Più avanti nel mio codice ho quanto segue:

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

Potrei definire gli elementi come IEnumerable?


3
Potete fornire maggiori informazioni sul tipo di _item e sulla firma di Get (stringa) (in particolare il tipo di ritorno)?
— Dr. Andrew Burnett-Thompson

Perché non cambiare il tipo in questo modo? public IEnumerable<Item> Items { get; set; }Hai qualche motivo speciale per averlo come ICollection?
— Shadow Wizard sta vaccinando il

IEnumerable <T> Get (string pk);
— Samantha JT Star

Risposte:


116

ICollection<T>eredita da IEnumerable<T>così per assegnare il risultato di

IEnumerable<T> Get(string pk)

a un ICollection<T>ci sono due modi.

// 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 seconda opzione è più flessibile, ma ha un impatto sulle prestazioni molto maggiore. Un'altra opzione è memorizzare il risultato come a IEnumerable<T>meno che non sia necessaria la funzionalità aggiuntiva aggiunta ICollection<T>dall'interfaccia.

Commento aggiuntivo sulle prestazioni

Il ciclo che hai

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

funziona su un IEnumerable<T>ma è inefficiente; ogni chiamata a Count()richiede un'enumerazione completa di tutti gli elementi. Usa una raccolta e la Countproprietà (senza parentesi) o convertila in un ciclo foreach:

foreach(var item in Items)

1
Qual è la funzionalità aggiuntiva aggiunta da ICollection?
— Samantha JT Star

7
ICollection<T>può essere manipolato (vedere il documento per i dettagli), mentre an IEnumerable<T>può essere solo enumerato.
— Anders Abel

Ho bisogno di qualcosa in cui posso eseguire diverse query LINQ. Non ho bisogno di aggiungere o fare nulla di simile all'elenco. Significa che starei meglio con ICollection.
— Samantha JT Star

LINQ funziona IEnumerable<T>quindi IEnumerable<T>è sufficiente in questo caso.
— Anders Abel

31

Non è possibile convertire direttamente da IEnumerable<T>a ICollection<T>. Puoi usare il ToListmetodo di IEnumerable<T>per convertirlo inICollection<T>

someICollection = SomeIEnumerable.ToList();


Questo funziona per me. Ma è una buona idea per me convertire o sarebbe meglio usare IEnumerable come tipo per gli elementi. Se utilizzo IEnumerable, lo faccio in modo da poter eseguire più azioni sugli elementi se necessario in seguito nel mio programma?
— Samantha JT Star

ICollection implementa già IEnumerable. Se sei preoccupato per le azioni disponibili, penso che dovresti scegliere ICollection. È meglio se puoi leggere l'effettiva differenza tra i due e poi decidere cosa vuoi effettivamente usare
— Haris Hasan

Sto cercando di capire quali vantaggi avrei se usassi ToList (). Una volta ottenuti i dati, vorrei eseguire query LINQ su elementi.
— Samantha JT Star

ToList () funzionerà ma come hai affermato nei tuoi commenti Get () restituisce un ICollection, quindi in realtà devi solo fare un cast a ICollection <T>, o meglio ancora, cambiare la firma di ritorno di Get to ICollection <T> . L'uso di ToList o ToArray funzionerà, ma comporterà anche un'operazione di creazione / copia di memoria non necessaria
— Dr. Andrew Burnett-Thompson

È possibile eseguire query LINQ su IEnumerable e ICollection. Vantaggi ... uno che so in questo momento è che Count ICollection mantiene il conteggio e IEnumerable restituisce il risultato calcolando il numero di articoli che ha. ICollection fornisce un metodo di rimozione aggiuntivo che Ienumerables non fa
— Haris Hasan

1

In attesa di maggiori informazioni sulla domanda:

si prega di fornire maggiori informazioni sul tipo di oggetto e la firma di Get

Due cose che puoi provare sono:

  • Per eseguire il cast del valore restituito di _item.Get to (ICollection)
  • in secondo luogo per utilizzare _item.Get ("001"). ToArray () o _item.Get ("001"). ToList ()

Si noti che il secondo subirà un calo delle prestazioni per la copia dell'array. Se la firma (tipo restituito) di Get non è una ICollection, la prima non funzionerà, se non è IEnumerable la seconda non funzionerà.


A seguito del tuo chiarimento alla domanda e nei commenti, dichiaro personalmente il tipo di restituzione di _item.Get ("001") a ICollection. Ciò significa che non dovrai eseguire alcun casting o conversione (tramite ToList / ToArray) che comporterebbe un'operazione di creazione / copia non necessaria.

// 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++) 

I migliori saluti,


1
La firma è: IEnumerable <T> Get (string pk); Gli elementi vengono utilizzati per contenere i record dell'articolo restituiti. Successivamente li ripeto per creare un report. Potrei usare qualsiasi cosa che funzioni. Quale pensi che sarebbe il miglior tipo di tipo di dati?
— Samantha JT Star

1
Suggerirei di modificare il tipo di dati di Items in IEnumerable <T> in modo che corrisponda a Get o di modificare il tipo di ritorno di Get to ICollection <T> in modo che corrisponda a Items. Presumo che questi due siano lo stesso tipo sottostante dichiarato in modo diverso? SE sono dello stesso tipo che si desidera evitare di utilizzare ToList () o ToArray () in quanto ciò esegue un'allocazione di memoria e una copia dell'array non necessarie. Se non sono dello stesso tipo devi fare qualche conversione
— Dr. Andrew Burnett-Thompson

Ho aggiunto alla domanda per mostrare dove sto utilizzando gli elementi in seguito. Hai ragione quando dici lo stesso tipo sottostante.
— Samantha JT Star

Ok, allora cambierei semplicemente il tipo restituito di Get, poiché non è necessario eseguire alcuna conversione (tramite ToList / ToArray, che è lento) o casting. Spero che questo aiuti :)
— Dr. Andrew Burnett-Thompson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.