Domanda

Sembra che un oggetto List non possa essere archiviato in una variabile List in C# e non possa nemmeno essere cast esplicitamente in questo modo.

List<string> sl = new List<string>();
List<object> ol;
ol = sl;

risulta in Impossibile convertire implicitamente il tipo System.Collections.Generic.List<string> A System.Collections.Generic.List<object>

Poi...

List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;

il risultato è Impossibile convertire il tipo System.Collections.Generic.List<string> A System.Collections.Generic.List<object>

Naturalmente, puoi farlo estraendo tutto dall'elenco delle stringhe e reinserindolo uno alla volta, ma è una soluzione piuttosto contorta.

È stato utile?

Soluzione

Pensatela in questo modo, se doveste fare un cast del genere e poi aggiungere un oggetto di tipo Foo all'elenco, l'elenco delle stringhe non sarebbe più coerente.Se dovessi iterare il primo riferimento, otterresti un'eccezione di cast della classe perché una volta colpita l'istanza Foo, Foo non potrebbe essere convertito in stringa!

Come nota a margine, penso che sarebbe più significativo se tu potessi o meno fare il cast inverso:

List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;

Non uso C# da un po', quindi non so se sia legale, ma quel tipo di cast è effettivamente (potenzialmente) utile.In questo caso si passa da una classe più generale (oggetto) a una classe più specifica (stringa) che si estende da quella generale.In questo modo, se aggiungi alla lista delle stringhe, non stai violando la lista degli oggetti.

Qualcuno sa o può verificare se un tale cast è legale in C#?

Altri suggerimenti

Se utilizzi .NET 3.5, dai un'occhiata al metodo Enumerable.Cast.È un metodo di estensione quindi puoi chiamarlo direttamente nella lista.

List<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();

Non è esattamente quello che hai chiesto, ma dovrebbe funzionare.

Modificare:Come notato da Zooba, puoi quindi chiamare ol.ToList() per ottenere un elenco

Non è possibile eseguire il cast tra tipi generici con parametri di tipo diversi.I tipi generici specializzati non fanno parte dello stesso albero ereditario e quindi sono tipi non correlati.

Per eseguire questa operazione prima di NET 3.5:

List<string> sl = new List<string>();
// Add strings to sl

List<object> ol = new List<object>();

foreach(string s in sl)
{
    ol.Add((object)s);  // The cast is performed implicitly even if omitted
}

Utilizzando Linq:

var sl = new List<string>();
// Add strings to sl

var ol = new List<object>(sl.Cast<object>());

// OR
var ol = sl.Cast<object>().ToList();

// OR (note that the cast to object here is required)
var ol = sl.Select(s => (object)s).ToList();

Il motivo è che una classe generica like List<> è, per la maggior parte degli scopi, trattata esternamente come una classe normale.per esempio.quando dici List<string>() dice il compilatore ListString() (che contiene stringhe).[Tecnici:questa è una versione estremamente semplice in inglese di quello che sta succedendo]

Di conseguenza, ovviamente il compilatore non può essere abbastanza intelligente da convertire una ListString in un ListObject eseguendo il cast degli elementi della sua raccolta interna.

Ecco perché esistono metodi di estensione per IEnumerable come Convert() che ti consentono di fornire facilmente la conversione per gli elementi archiviati all'interno di una raccolta, il che potrebbe essere semplice come passare dall'uno all'altro.

Ciò ha molto a che fare con la covarianza, ad esempio i tipi generici sono considerati parametri e se i parametri non si risolvono correttamente in un tipo più specifico, l'operazione fallisce.L'implicazione di ciò è che in realtà non è possibile eseguire il cast su un tipo più generale come oggetto.E come affermato da Rex, l'oggetto List non convertirà ogni oggetto per te.

Potresti invece provare il codice ff:

List<string> sl = new List<string>();
//populate sl
List<object> ol = new List<object>(sl);

O:

List<object> ol = new List<object>();
ol.AddRange(sl);

ol copierà (teoricamente) tutto il contenuto di sl senza problemi.

Sì, puoi, da .NET 3.5:

List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();

Mike - Credo che la controvarianza non sia consentita neanche in C#

Vedere Varianza dei parametri di tipo generico in CLR per qualche informazione in più.

Penso che questa (controvarianza) sarà effettivamente supportata in C# 4.0.http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx

In realtà è così che non provi a inserire alcun "oggetto" strano nella tua variante di lista "ol" (come List<object> sembrerebbe consentire) - perché il tuo codice si bloccherebbe in quel caso (perché l'elenco lo è davvero List<string> e accetterà solo oggetti di tipo String).Ecco perché non puoi trasformare la tua variabile in una specifica più generale.

Su Java è il contrario, non hai generici, e invece tutto è Elenco di oggetti in fase di esecuzione e puoi davvero inserire qualsiasi oggetto strano nella tua Lista presumibilmente rigorosamente tipizzata.Cerca "Reified generics" per vedere una discussione più ampia sul problema di Java...

Tale covarianza sui generici non è supportata, ma puoi effettivamente farlo con gli array:

object[] a = new string[] {"spam", "eggs"};

C# esegue controlli di runtime per impedirti di inserire, ad esempio, un file int in a.

Ecco un'altra soluzione precedente a .NET 3.5 per qualsiasi IList il cui contenuto può essere sottoposto a cast in modo implicito.

public IList<B> ConvertIList<D, B>(IList<D> list) where D : B
{
    List<B> newList = new List<B>();

    foreach (D item in list)
    {
        newList.Add(item);
    }

    return newList;
}

(Basato sull'esempio di Zooba)

Ho un:

private List<Leerling> Leerlingen = new List<Leerling>();

E stavo per riempirlo con i dati raccolti in un file List<object>Ciò che alla fine ha funzionato per me è stato questo:

Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();

.Cast al tipo che desideri ottenere IEnumerable da quel tipo, quindi digita il file IEnemuerable al List<> tu vuoi.

Mm, grazie ai commenti precedenti ho trovato due modi per scoprirlo.Il primo è ottenere l'elenco di stringhe di elementi e quindi trasmetterlo all'elenco di oggetti IEnumerable:

IEnumerable<object> ob;
List<string> st = new List<string>();
ob = st.Cast<object>();

E il secondo è evitare il tipo di oggetto IEnumerable, semplicemente trasmettendo la stringa al tipo di oggetto e quindi utilizzando la funzione "toList()" nella stessa frase:

List<string> st = new List<string>();
List<object> ob = st.Cast<object>().ToList();

Mi piace di più il secondo modo.Spero che aiuti.

List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top