.net - significado - Lógica y su aplicación a colecciones. Genérico y herencia
logica simbolica (6)
A primera vista, esto no tiene sentido intuitivo. Pero lo hace. Mira este código:
List<Person> people = new List<Person>();
List<object> things = people; // this is not allowed
// ...
Mouse gerald = new Mouse();
things.add(gerald);
Ahora, de repente, tenemos una List
de objetos Person
... ¡con un Mouse
dentro!
Esto explica por qué la asignación de un objeto de tipo A<T>
a una variable de tipo A<S>
no está permitida, incluso si S
es un supertipo de T
Todo hereda de un objeto. Es la base de la herencia. Todo se puede convertir implícitamente en el árbol de herencia, es decir.
object me = new Person();
Por lo tanto, siguiendo esto hasta su conclusión lógica, un grupo de personas también sería un grupo de objetos:
List<Person> people = new List<Person>();
people.Add(me);
people.Add(you);
List<object> things = people; // Ooops.
Excepto que eso no funcionará, las personas que diseñaron .NET o lo pasaron por alto, o hay una razón, y no estoy seguro de cuál. Al menos una vez me encontré con una situación en la que esto hubiera sido útil, pero tuve que terminar usando un hack desagradable (subclasificando Lista solo para implementar un operador de conversión).
La pregunta es esta: ¿hay alguna razón para este comportamiento? ¿Hay una solución más simple para obtener el comportamiento deseado?
Para el registro, creo que la situación en la que quería este tipo de comportamiento era una función de impresión genérica que mostraba listas de objetos llamando a ToString () y formateando las cadenas de forma agradable.
Con los métodos de extensión linq puedes hacer
IEnumerable<object> things = people.Cast<object>();
List<object> things = people.Cast<object>().ToList();
De lo contrario, ya que está escribiendo fuertemente la lista, la conversión implícita no está permitida.
De acuerdo, todos los que han usado genéricos en .net deben haberse topado con esto en un punto u otro.
Sí, intuitivamente debería funcionar. No, en la versión actual del compilador de C # no es así.
Eric Lippert tiene una muy buena explicación de este tema (está en once partes o algo y te hará pensar en algunos lugares, pero vale la pena leerlo). Mira aquí .
editar:
busqué otro enlace relevante, este discute cómo java maneja esto. Mira aquí
La solución de linq es buena. Otra solución, ya que está utilizando el tipo de objeto, es pasar la lista como IEnumerable (no la versión genérica).
Editar : C # 4 (actualmente beta) admite un parámetro de tipo covariante en IEnumerable. Si bien no podrá asignar directamente a una Lista <objeto>, puede pasar su lista a un método que espera un <objeto> IEnumerable.
Si bien lo que intentas de hecho fluye lógicamente, en realidad es una característica que muchos idiomas no admiten de forma nativa. Esto es lo que se llama varianza co / contra, que tiene que ver con cuándo y cómo los objetos pueden ser implícitamente emitidos de una cosa a otra por un compilador. Afortunadamente, C # 4.0 traerá covarianza y contravarianza a la arena C #, y tales conversiones implícitas como esta deberían ser posibles.
Para una explicación detallada de esto, el siguiente video de Channel9 debería ser útil:
puedes usar linq para lanzarlo:
IEnumerable<Person> oldList = someIenumarable;
IEnumerable<object> newList = oldlist.Cast<object>()