No asistí a PDC 2008, pero escuché algunas noticias de que C # 4.0 se anunció para admitir la covarianza y contravarianza genéricas. Es decir, List<string>
se puede asignar a List<object>
. ¿Cómo es posible?
En el libro C # in Depth de Jon Skeet , se explica por qué los genéricos de C # no admiten la covarianza y la contravarianza. Es principalmente para escribir código seguro. Ahora, C # 4.0 cambió para admitirlos. ¿Traería el caos?
¿Alguien sabe los detalles sobre C # 4.0 puede dar alguna explicación?
c#
c#-4.0
covariance
contravariance
generic-variance
Morgan Cheng
fuente
fuente
Respuestas:
La varianza solo se admitirá de manera segura ; de hecho, utilizando las habilidades que ya tiene el CLR. Entonces, los ejemplos que doy en el libro de tratar de usar a
List<Banana>
comoList<Fruit>
(o lo que sea) todavía no funcionarán, pero algunos otros escenarios sí lo harán.En primer lugar, solo será compatible con interfaces y delegados.
En segundo lugar, requiere que el autor de la interfaz / delegado decore los parámetros de tipo como
in
(para contravarianza) oout
(para covarianza). El ejemplo más obvio es elIEnumerable<T>
que sólo le permite quitarle valores, no le permite agregar valores nuevos. Eso se convertiráIEnumerable<out T>
. Eso no perjudica la seguridad de tipos en absoluto, pero le permite devolver unIEnumerable<string>
de un método declarado para devolver,IEnumerable<object>
por ejemplo.La contravarianza es más difícil de dar ejemplos concretos para el uso de interfaces, pero es fácil con un delegado. Considere
Action<T>
: eso solo representa un método que toma unT
parámetro. Sería bueno poder convertir sin problemas el uso de anAction<object>
comoAction<string>
: cualquier método que tome unobject
parámetro estará bien cuando se presente con unstring
. Por supuesto, C # 2 ya tiene covarianza y contravarianza de delegados hasta cierto punto, pero a través de una conversión real de un tipo de delegado a otro (creando una nueva instancia); consulte P141-144 para ver ejemplos. C # 4 hará que esto sea más genérico y (creo) evitará crear una nueva instancia para la conversión. (En su lugar, será una conversión de referencia).Espero que esto lo aclare un poco; ¡avíseme si no tiene sentido!
fuente
List<Banana>
comoIList<Fruit>
" como dijo @ Ark-kun? Si es así, cómo es posible, aunque el parámetro de tipo de laIList<T>
interfaz no está definido como covariante (noout T
, sino simplementeT
).No es que Jon no lo haya cubierto ya, pero aquí hay algunos enlaces a blogs y videos de Eric Lippert. Hace un buen trabajo al explicarlo con ejemplos.
https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/
Los videos:
https://www.youtube.com/watch?v=3MQDrKbzvqU
https://www.youtube.com/watch?v=XRIadQaBYlI
https://www.youtube.com/watch?v=St9d2EDZfrg
fuente