Pregunta

Parece que un objeto List no se puede almacenar en una variable List en C#, y ni siquiera se puede convertir explícitamente de esa manera.

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

da como resultado No se puede convertir implícitamente el tipo System.Collections.Generic.List<string> a System.Collections.Generic.List<object>

Y luego...

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

resultados en No se puede convertir el tipo System.Collections.Generic.List<string> a System.Collections.Generic.List<object>

Por supuesto, puedes hacerlo sacando todo de la lista de cadenas y volviéndolo a colocar uno a la vez, pero es una solución bastante complicada.

¿Fue útil?

Solución

Piénselo de esta manera, si hiciera dicha conversión y luego agregara un objeto de tipo Foo a la lista, la lista de cadenas ya no sería consistente.Si iteraras la primera referencia, obtendrías una excepción de conversión de clase porque una vez que llegas a la instancia de Foo, ¡Foo no se puede convertir en una cadena!

Como nota al margen, creo que sería más importante si puedes o no hacer el reparto inverso:

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

No he usado C# desde hace tiempo, así que no sé si eso es legal, pero ese tipo de conversión es realmente (potencialmente) útil.En este caso, estás pasando de una clase (objeto) más general a una clase (cadena) más específica que se extiende desde la general.De esta manera, si agrega a la lista de cadenas, no está violando la lista de objetos.

¿Alguien sabe o puede probar si dicha conversión es legal en C#?

Otros consejos

Si está utilizando .NET 3.5, eche un vistazo al método Enumerable.Cast.Es un método de extensión por lo que puedes llamarlo directamente en la Lista.

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

No es exactamente lo que pediste, pero debería funcionar.

Editar:Como lo señaló Zooba, luego puede llamar a ol.ToList() para obtener una Lista

No se puede convertir entre tipos genéricos con diferentes parámetros de tipo.Los tipos genéricos especializados no forman parte del mismo árbol de herencia y, por lo tanto, son tipos no relacionados.

Para hacer esto antes de 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
}

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

La razón es que una clase genérica como List<> se trata, para la mayoría de los propósitos, externamente como una clase normal.p.ej.cuando tu dices List<string>() el compilador dice ListString() (que contiene cadenas).[Gente técnica:esta es una versión en inglés extremadamente sencilla de lo que está pasando]

En consecuencia, obviamente el compilador no puede ser lo suficientemente inteligente como para convertir un ListString en un ListObject emitiendo los elementos de su colección interna.

Es por eso que existen métodos de extensión para IEnumerable como Convert() que le permiten proporcionar fácilmente la conversión de los elementos almacenados dentro de una colección, lo que podría ser tan simple como convertir de uno a otro.

Esto tiene mucho que ver con la covarianza; por ejemplo, los tipos genéricos se consideran parámetros y, si los parámetros no se resuelven correctamente en un tipo más específico, la operación falla.La implicación de esto es que realmente no se puede convertir a un tipo de objeto más general.Y como lo indicó Rex, el objeto Lista no convertirá cada objeto por usted.

Quizás quieras probar el código ff en su lugar:

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 copiará (teóricamente) todo el contenido de sl sin problemas.

Sí, puedes, desde .NET 3.5:

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

Mike: Creo que la contravarianza tampoco está permitida en C#

Ver Variación de parámetros de tipo genérico en CLR para más información.

En realidad, eso es para que no intentes poner ningún "objeto" extraño en tu variante de lista "ol" (como List<object> parecería permitir) - porque su código fallaría en ese momento (porque la lista realmente es List<string> y sólo aceptará objetos de tipo String).Es por eso que no puedes convertir tu variable a una especificación más general.

En Java es al revés, no tienes genéricos y, en cambio, todo es una Lista de objetos en tiempo de ejecución, y realmente puedes incluir cualquier objeto extraño en tu Lista supuestamente estrictamente tipificada.Busque "genéricos reificados" para ver una discusión más amplia sobre el problema de Java...

Esta covarianza en genéricos no es compatible, pero puedes hacerlo con matrices:

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

C# realiza comprobaciones en tiempo de ejecución para evitar que coloques, por ejemplo, un int en a.

Aquí hay otra solución anterior a .NET 3.5 para cualquier IList cuyo contenido se pueda transmitir implícitamente.

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;
}

(Basado en el ejemplo de Zooba)

Tengo un:

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

Y lo iba a llenar con datos recopilados en un List<object>Lo que finalmente funcionó para mí fue este:

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

.Cast al tipo que desea obtener IEnumerable de ese tipo, luego encasilla el IEnemuerable hacia List<> quieres.

Mm, gracias a comentarios anteriores encontré dos formas de averiguarlo.El primero es obtener la lista de cadenas de elementos y luego convertirla en la lista de objetos IEnumerable:

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

Y el segundo es evitar el tipo de objeto IEnumerable, simplemente convertir la cadena al tipo de objeto y luego usar la función "toList()" en la misma oración:

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

Me gusta más la segunda forma.Espero que esto ayude.

List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top