2012-01-19 9 views
41

Come posso trasmettere un List<object> a List<SomethingElse>?Come trasmettere l'elenco <object> a Elenco <SomethingElse>

(dove SomethingElse è noto a scendere dal object)


Bonus Chatter

Casting lista:

List<Object> first = ...; 

List<SomethingElse> second = (List<SomethingElse>)first; 

non funziona:

Impossibile convertire il tipo 'System.Collections.Generic.List' a 'System.Collections.Generic.List'

Casting lista:

List<SomethingElse> second = first.Cast<SomethingElse>(); 

non funziona:

Impossibile implicitamente convertire il tipo 'System.Collections.Generic.List' a 'System.Collections.Generic.List'

io in realtà non hanno bisogno della piena List<T> oggetto, solo un ICollection<T> farà:

ICollection<SomethingElse> second = first; 
ICollection<SomethingElse> second = (ICollection<SomethingElse>)first; 
ICollection<SomethingElse> second = first.Cast<SomethingElse>(); 

non funzionano.

+0

correlati? http://stackoverflow.com/questions/1266014/c-sharp-casting-a-listobjbase-as-listobj – eldarerathis

+0

Eventuale duplicato di http://stackoverflow.com/questions/7955890/how-to-cast-listclassb-to -listclassa-when-classb-inherits-from-classa – dash

+0

Funzionerebbe? Elenca secondo = first.Select (o => (SomethingElse) o) .ToList(); – asmo

risposta

31

LINQ, attuato attraverso i metodi di estensione all'interno della classe Enumerable, deduce esecuzione differita:

metodi che vengono utilizzati in una query che restituisce una sequenza di valori non consumare i dati di destinazione finché la query oggetto è elencato. Questo è noto come esecuzione differita.

Cast<T> non crea immediatamente un nuovo elenco, ma memorizza tutte le informazioni necessarie per eseguire l'azione. L'elenco viene enumerato solo quando richiesto (ad esempio, tramite una dichiarazione foreach).

Nel tuo caso, se semplicemente intenzione di iterare la sequenza, si dovrebbe considerare attaccare all'interfaccia IEnumerable<T>, che è il tipo di ritorno dichiarato di Cast<T>:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>(); 
foreach (SomethingElse se in second) 
{ 
    // ... 
} 

Questa è efficiente, dal momento che solo esegue il cast come ogni elemento viene iterato.

Se sei convinto che si desidera una nuova lista da creare immediatamente, utilizzare ToList:

List<SomethingElse> second = first.Cast<SomethingElse>().ToList(); 

Edit: Risposta a punto pubblicato in commento:

Dipende da cosa si intende da "una lista che può essere modificata". Esistono diversi operatori di query LINQ che consentono di modificare ulteriormente la definizione della query. Ad esempio, se si desidera rimuovere tutti SomethingElse elementi i cui IsDeleted proprietà è true, è possibile utilizzare l'Where dell'operatore:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>(); 
second = second.Where(element => !element.IsDeleted); 

Se si desidera aggiungere una sequenza di nuovi elementi, è possibile utilizzare l'operatore Concat:

second = second.Concat(anotherCollectionOfSomethingElse); 

Se si desidera ordinare la sequenza in ordine crescente di ID, utilizzare il OrderBy dell'operatore:

second = second.OrderBy(element => element.ID); 

Ogni volta, stiamo applicando un operatore di query sopra l'ex definizione della nostra query e assegnare il nuovo (composito) query per la nostra variabile second. LINQ memorizzerebbe tutti i tuoi operatori nella definizione della query. Poi, quando la sequenza è effettivamente enumerato (ad esempio, attraverso un foreach o ToList), si darebbe il risultato composito della sequenza, con tutti gli operatori di query applicati in ordine.

Come in tutti i casi di esecuzione differita/valutazione pigra, fare attenzione a non esagerare con questo. Se, per esempio, si sta andando ad applicare un operatore Where che ridurrà la dimensione della sequenza drasticamente, potrebbe avere senso per eseguire la query con entusiasmo e memorizzare la lista numerata, invece.

+0

Non ho bisogno di creare una nuova lista immediatamente; ma ho bisogno di una lista che possa essere modificata e non limitata dal problema della covarianza. Se 'ToList' è ciò di cui ho bisogno per ottenere ciò di cui ho bisogno, ho bisogno di usarlo. Preferirei, naturalmente, che l''Elenco' restituito fosse un wrapper attorno al' primo', consentendo anche l'esecuzione differita. –

13

penso che sei vicino alla Cast<T> espressione. La differenza è che Cast<T> restituisce un IEnumerable<T>, non uno List<T>.

Prova questo:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>(); 

È possibile ottenere un elenco facendo qualcosa di simile:

List<SomethingElse> second = first.Cast<SomethingElse>().ToList(); 
9

Hai la possibilità di utilizzare sia Cast o OfType. Cast genererà un'eccezione se non puoi trasmettere al tipo specificato. OfType restituirà solo gli elementi nell'elenco che è possibile trasmettere al tipo specificato. Ti consiglio di utilizzare OfType nella tua situazione.

List<Foo> fooList = myList.OfType<Foo>().ToList(); 
Problemi correlati