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.