En C #, ¿por qué no se puede almacenar un objeto List en una variable List ?

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

List sl = new List(); List ol; ol = sl; 

resultados en No se puede convertir implícitamente el tipo System.Collections.Generic.List a System.Collections.Generic.List

Y entonces…

 List sl = new List(); List ol; ol = (List)sl; 

resultados en No se puede convertir el tipo System.Collections.Generic.List en System.Collections.Generic.List

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

Piénselo de esta manera, si tuviera que hacer un molde de ese tipo, y luego agregar un objeto de tipo Foo a la lista, la lista de cadenas ya no es consistente. Si tuviera que repetir la primera referencia, obtendría una excepción de lanzamiento de clase porque una vez que golpeó la instancia de Foo, ¡el Foo no se pudo convertir a la secuencia!

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

 List ol = new List(); List sl; sl = (List)ol; 

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

¿Alguien sabe o puede probar si tal yeso es legal en C #?

Si usa .NET 3.5, eche un vistazo al método Enumerable.Cast. Es un método de extensión para que pueda llamarlo directamente en la Lista.

 List sl = new List(); IEnumerable ol; ol = sl.Cast(); 

No es exactamente lo que pediste, pero debería hacer el truco.

Editar: como señaló Zooba, puede llamar a ol.ToList () para obtener una lista

No puede convertir tipos generics con parámetros de tipos diferentes. Los tipos generics especializados no forman parte del mismo árbol de herencia y, por lo tanto, son tipos no relacionados.

Para hacer esto pre-NET 3.5:

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

Usando Linq:

 var sl = new List(); // Add strings to sl var ol = new List(sl.Cast()); // OR var ol = sl.Cast().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<> es, para la mayoría de los propósitos, tratada externamente como una clase normal. por ejemplo, cuando dices List() el comstackdor dice ListString() (que contiene cadenas). [Gente técnica: esta es una versión extremadamente simple, ilustrada en inglés de lo que está pasando]

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

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

Esto tiene mucho que ver con la covarianza, por ejemplo, los tipos generics se consideran como parámetros, y si los parámetros no se resuelven correctamente a un tipo más específico, la operación falla. La implicación de tal es que realmente no se puede convertir a un tipo más general como objeto. Y según lo establecido por Rex, el objeto List no convertirá cada objeto por usted.

Es posible que desee probar el código ff en su lugar:

 List sl = new List(); //populate sl List ol = new List(sl); 

o:

 List ol = new List(); ol.AddRange(sl); 

Ol (teóricamente) copiará todos los contenidos de sl sin problemas.

Sí, puede, desde .NET 3.5:

 List sl = new List(); List ol = sl.Cast().ToList(); 

Mike: creo que la contravariancia tampoco está permitida en C #

Consulte Varianza de parámetros de tipo genérico en CLR para obtener más información.

Eso es en realidad para que no trates de poner ningún “objeto” extraño en tu “lista” (como lo haría List ) porque tu código se bloqueará (porque la lista realmente es List y solo aceptará objetos 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 tiene generics, y en su lugar todo es Lista de objetos en tiempo de ejecución, y realmente puede rellenar cualquier objeto extraño en su Lista supuestamente estrictamente tipada. Busque “Genéricos reificados” para ver una discusión más amplia del problema de Java …

Tal covarianza en generics no es compatible, pero en realidad puedes hacer esto con matrices:

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

C # realiza comprobaciones de tiempo de ejecución para evitar que ponga, digamos, un int en a .

Aquí hay otra solución de pre.NET 3.5 para cualquier IList cuyos contenidos se puedan convertir implícitamente.

 public IList ConvertIList(IList list) where D : B { List newList = new List(); foreach (D item in list) { newList.Add(item); } return newList; } 

(Basado en el ejemplo de Zooba)

Tengo un:

 private List Leerlingen = new List(); 

E iba a completarlo con datos recostackdos en una List Lo que finalmente funcionó para mí fue este:

 Leerlingen = (List)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast(); 

.Cast en el tipo que desea para obtener un IEnumerable de ese tipo, luego encasille el IEnemuerable en la List<> que desee.

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

 IEnumerable ob; List st = new List(); ob = st.Cast(); 

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

 List st = new List(); List ob = st.Cast().ToList(); 

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

 List sl = new List(); List ol; ol = new List(sl);