2010-03-29 18 views
18

¿Cuál es la razón real por esa limitación? ¿Es solo trabajo lo que debe hacerse? ¿Es conceptualmente difícil? ¿Es imposible?¿Por qué C# (4.0) no permite co y contravariancia en tipos de clases genéricas?

Seguro, no se podían usar los parámetros de tipo en los campos, porque son siempre de lectura-escritura. Pero esa no puede ser la respuesta, ¿verdad?

El motivo de esta pregunta es que estoy escribiendo un artículo sobre soporte de varianza en C# 4, y creo que debería explicar por qué está restringido a delegados e interfaces. Solo para invertir la carga de la prueba.

Actualización: Eric preguntó sobre un ejemplo.

¿Qué hay de esto (no sé si eso tiene sentido, sin embargo :-))

public class Lookup<out T> where T : Animal { 
    public T Find(string name) { 
    Animal a = _cache.FindAnimalByName(name); 
    return a as T; 
    } 
} 

var findReptiles = new Lookup<Reptile>(); 
Lookup<Animal> findAnimals = findReptiles; 

La razón de tener que en una clase podría ser el caché que se llevó a cabo en la propia clase. ¡Y por favor no nombre a sus diferentes mascotas de la misma forma!

Por cierto, esto me lleva a optional type parameters in C# 5.0 :-)

Actualización 2: No estoy afirmando que el CLR y C# debería permitir esto. Solo estoy tratando de entender lo que me llevó a eso.

+1

Claro, ese es un ejemplo razonable pero no ha mostrado nada que tampoco se pueda hacer con las interfaces. Simplemente haga la interfaz ILookup y haga que Lookup lo implemente. ¿Qué beneficio adicional convincente sobre la varianza de la interfaz agrega su escenario para la varianza de clase? –

+1

Ninguno, en realidad. Además de eso, es menos código. Permítanme invertir la carga de la prueba. ¿Cómo podríamos explicar por qué no es compatible? No estoy pidiendo implementarlo, en realidad. "¡Siempre ha sido así" no cuenta! :-) –

+0

No tenemos que proporcionar una justificación para * no * implementar una función. No implementar una característica es * gratis *. Por el contrario, tenemos que proporcionar una justificación para implementar una característica: las características pueden costar millones de dólares a Microsoft e imponer una carga aún mayor a nuestros clientes, que luego deben gastar tiempo y dinero aprendiendo sobre la función. –

Respuesta

18

En primer lugar, como dice Tomás, que no se admite en el CLR.

En segundo lugar, ¿cómo funcionaría? Supongamos que tiene

class C<out T> 
{ ... how are you planning on using T in here? ... } 

T solo se puede utilizar en las posiciones de salida. Como nota, la clase no puede tener ningún campo de tipo T porque el campo podría escribirse. La clase no puede tener ningún método que tome una T, porque lógicamente se escribe. Supongamos que tiene esta característica: ¿cómo podría aprovecharla?

Esto sería útil para clases inmutables si pudiéramos, por ejemplo, hacer legal tener un campo de solo lectura de tipo T; De esa forma, redujimos masivamente la probabilidad de que se escribiera incorrectamente. Pero es bastante difícil encontrar otros escenarios que permitan la variación de una manera segura.

Si tiene este tipo de escenario, me encantaría verlo. Eso sería puntos para algún día implementar esto en el CLR.

ACTUALIZACIÓN: Ver

Why isn't there generic variance for classes in C# 4.0?

para más información sobre esta cuestión.

+1

Buena pregunta :) Recuerdo una discusión entre Anders y algunos geek compiladores de Java (lo siento) en Lang.NET el año pasado, donde el Java-guy pidió esta característica. Parecía saber por qué preguntó. Pero no puedo recordar. Pensé en clases sin estado.Intentaré inventar algo en la pregunta. –

+1

Esta sería definitivamente una buena característica para tipos de datos inmutables como 'Tuple ', pero estoy de acuerdo en que esto no es lo suficientemente convincente para cambiar el CLR :-). –

+3

Otro caso de uso son los tipos fantasma donde la T solo se usa para la seguridad del tipo y no en la implementación de la clase. – porges

8

Hasta donde yo sé, esta función no es compatible con CLR, por lo que agregar esto también requeriría un trabajo importante en el lado de CLR. Creo que la contra varianza para las interfaces y los delegados en realidad era compatible con CLR antes de la versión 4.0, por lo que esta fue una extensión relativamente sencilla de implementar.

(Apoyando esta característica para las clases serían sin duda útil, sin embargo!)

+0

Tienes razón. La varianza en los params de tipo genérico de interfaces y delegados vino con CLR 2.0, simplemente no en C# –

1

Si se permitieran, se podrían definir clases o estructuras útiles 100% tipo seguro (sin tipografías internas) que fueran covariantes con respecto a su tipo T, si su constructor aceptara una o más empresas T o T. Se podrían definir clases o estructuras útiles, 100% de tipo seguro, que fueran contravariantes con respecto a T si sus constructores aceptaran uno o más consumidores de T. No estoy seguro de que haya mucha ventaja de una clase sobre una interfaz, más allá de la capacidad de usar "nuevo" en lugar de utilizar un método de fábrica estático (muy probablemente de una clase cuyo nombre es similar al de la interfaz), pero puedo sin duda, los casos de uso para tener estructuras inmutables apoyan la covarianza.

Cuestiones relacionadas