2008-10-29 14 views
103

No asistí a PDC 2008, pero escuché algunas noticias de que C# 4.0 se anuncia para admitir la covarianza y la contravariancia genéricas. Es decir, List<string> se puede asignar a List<object>. ¿Cómo es posible?¿Cómo se implementa la covarianza y contra varianza genéricas en C# 4.0?

En Jon Skeet libro C# en profundidad, se explica por qué los genéricos de C# no es compatible con la covarianza y contra-varianza. Es principalmente para escribir código de seguridad. Ahora, C# 4.0 cambió para darles soporte. ¿Traería caos?

¿Alguien sabe los detalles sobre C# 4.0 puede dar alguna explicación?

+0

Aquí es un buen artículo que cubre los próximos covarianza y contra-varianza implementaciones sobre los delegados y las interfaces de C# 4.0: [LINQ Farm: covarianza y contravarianza en C# 4.0] (http://blogs.msdn.com/charlie/archive/2008/10/28/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx) – CMS

+0

Anders Noråse explica en [C# 4.0 - Covarianza y contravariancia] (http://web.archive.org/web/20100227031805/http://andersnoras.com/post/100795246/c-4-0-covariance-and-contra-variance) concepto y muestra, que ya es compatible hoy en IL desde .NET 2.0. –

Respuesta

152

La varianza solo se admitirá en una forma segura - de hecho, utilizando las capacidades que ya tiene el CLR. Así que los ejemplos que doy en el libro de intentar usar un List<Banana> como List<Fruit> (o lo que sea) todavía no funcionarán, pero algunos otros escenarios sí.

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 la contravarianza) o out (para la covarianza). El ejemplo más obvio es IEnumerable<T> que solo le permite tomar valores "fuera" de él, no le permite agregar otros nuevos. Eso se convertirá en IEnumerable<out T>. Eso no daña la seguridad del tipo en absoluto, pero le permite devolver un IEnumerable<string> de un método declarado para devolver IEnumerable<object>, por ejemplo.

La contradicción es más difícil de dar ejemplos concretos para el uso de interfaces, pero es fácil con un delegado. Considere Action<T> - que solo representa un método que toma un parámetro T. Sería bueno poder convertir a la perfección el uso de Action<object> como Action<string> - cualquier método que tome un parámetro object va a estar bien cuando se presente con un string en su lugar. Por supuesto, C# 2 ya tiene covarianza y contravariancia 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) - vea P141-144 para ejemplos. C# 4 lo hará 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, por favor avíseme si no tiene sentido.

+3

Entonces, ¿significa que si la clase se declara como "List " entonces NO debería tener una función de miembro como "void Add (T obj)"? El compilador de C# 4.0 informará el error sobre eso, ¿verdad? –

+1

Morgan: Eso es ciertamente mi entendimiento, sí. –

+4

una vez más, una de sus respuestas aquí en SO me ayudó de inmediato a mejorar algunos códigos. ¡Gracias! – Mark

Cuestiones relacionadas