ultimo - En C#, ¿por qué no se puede almacenar un objeto List<string> en una variable List<object>
obtener elemento de una lista c# (14)
Parece que un objeto de Lista no se puede almacenar en una variable de Lista en C #, y ni siquiera se puede convertir explícitamente de esa manera.
List<string> sl = new List<string>();
List<object> ol;
ol = sl;
no se pueden convertir implícitamente el tipo
System.Collections.Generic.List<string>
a
System.Collections.Generic.List<object>
Y entonces...
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, puede hacerlo sacando todo de la lista de cadenas y volviéndolo a poner uno a la vez, pero es una solución bastante complicada.
Aquí hay otra solución pre- .NET 3.5 para cualquier IList cuyo contenido pueda ser emitido 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)
Creo que esta (contravarianza) será soportada en C # 4.0. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
Dicha covarianza en los genéricos no es compatible, pero en realidad puede hacer esto con matrices:
object[] a = new string[] {"spam", "eggs"};
C # realiza verificaciones de tiempo de ejecución para evitar que coloque, por ejemplo, un
int
en
a
.
Eso es en realidad para que no intentes poner ningún "objeto" impar en tu variante de la lista "ol" (como parece que la
List<object>
permitiría) - porque tu código se bloquearía entonces (porque la lista realmente es
List<string>
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 genéricos, 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 de tipos supuestamente estrictos. Busque "Genéricos reificados" para ver una discusión más amplia del problema de Java ...
Esto tiene mucho que ver con la covarianza, por ejemplo, los tipos genéricos 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 esto es que realmente no se puede convertir a un tipo similar a un objeto más general. 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<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 (teóricamente) copiará todos los contenidos de sl sin problemas.
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 dice
List<string>()
el compilador dice
ListString()
(que contiene cadenas).
[Gente técnica: esta es una versión extremadamente simple de lo que está pasando en inglés]
En consecuencia, obviamente el compilador no puede ser lo suficientemente inteligente como para convertir un ListString en un ListObject al lanzar los elementos de su colección interna.
Es por eso que hay 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 la conversión de uno a otro.
Mike: creo que la contravarianza no está permitida en C # tampoco
Consulte Varianza de parámetros de tipo genérico en el CLR para obtener más información.
Mm, gracias a los comentarios anteriores encontré dos maneras de averiguarlo. El primero es obtener la lista de elementos de la cadena 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 en 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.
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 pre-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();
Piénselo de esta manera, si tuviera que hacer una conversión 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 conversión de clase porque una vez que llegara a la instancia de Foo, ¡no se podría convertir a Foo en una cadena!
Como nota al margen, creo que sería más significativo si puedes o no hacer el lanzamiento inverso:
List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;
No he usado C # por un tiempo, así que no sé si eso es legal, pero ese tipo de reparto es realmente (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 manera, si agrega a la lista de cadenas, no está violando la lista de objetos.
¿Alguien sabe o puede probar si dicho reparto es legal en C #?
Sí, puedes, desde .NET 3.5:
List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();
Si está utilizando .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<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();
No es exactamente lo que pediste pero debería hacer el truco.
Edición: Como lo señaló Zooba, puede llamar a ol.ToList () para obtener una lista
Tengo un:
private List<Leerling> Leerlingen = new List<Leerling>();
Y lo iba a llenar con los datos recopilados en una
List<object>
Lo que finalmente me funcionó fue este:
Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();
.Cast
al tipo que desee para obtener un
IEnumerable
de ese tipo y, a continuación,
IEnemuerable
en la
List<>
que desee.
List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);