2010-05-11 9 views
6

¿Puedo tener un tipo (por ahora olvidando su semántica) que puede ser covariante y también contravariante?¿Puedo tener un tipo que sea ambos, covariante y contravariante, es decir, completamente fungible/modificable con sub y super tipos?

por ejemplo:

public interface Foo<in out T> 
{ 
    void DoFooWith(T arg); 
} 

Off para el blog de Eric Lippert para la carne y las patatas de la varianza en C# 4.0 como hay poco más en cualquier lugar que cubre de tierra adecuada sobre el tema.


lo intenté de todas formas, no sólo no permite eso, pero me dice que me falta el punto. Necesito entender el vínculo entre solo lectura, solo escritura y varianza.

Supongo que tengo que leer un poco más.

Pero cualquier respuesta breve, epifanía inductora es bienvenida, mientras tanto.

Respuesta

7

No, no puedes hacer eso.

Supongamos que fuera legal. Usted hace un IFoo<Giraffe>. Como IFoo es covariante en T, puede convertirlo a través de una conversión de referencia segura a IFoo<object>. Como es contravariante, puede convertir eso a IFoo<Banana>. ¿Qué semántica posible existe para IFoo<T> de modo que tenga sentido poder convertir un IFoo de jirafas en un IFoo de plátanos mediante conversión de referencia? Las jirafas y los plátanos no tienen nada en común más que ser tipos de referencia. No es posible tener un método en IFoo<Banana> que devuelva un Banana, porque podría ser una implementación de IFoo<Giraffe>; ¿Cómo sabría el autor de la implementación repartir un plátano? No es posible tener un método en IFoo<Banana> que tome una banana por la misma razón; el implementador de IFoo<Giraffe> espera que le entregues una jirafa.

Ésta es otra manera de ver las cosas:

  • "en T" significa (más o menos) "T aparece sólo en posiciones de entrada".
  • "out T" significa (aproximadamente) "T aparece solo en las posiciones de salida".

Por lo tanto, "in out T" significaría ... ¿qué? Como ya hemos visto, solo puede significar que "T no aparece en absoluto en ningún método o propiedad". ¿Cuál es el punto de hacer un tipo genérico en T donde nunca usas T?

+1

En realidad, los tipos genéricos que no utilizan sus argumentos de tipo genérico pueden ser extremadamente útiles. Los llamados "tipos fantasma" permiten que el código se escriba de tal manera que las operaciones incorrectas se pueden rechazar estáticamente. El ejemplo canónico es probablemente el tipo 'Archivo ', donde el tipo 'T' codifica si el archivo permite leer, escribir o ambos aunque las partes internas de la clase nunca hagan referencia a 'T'. – kvb

+0

Por supuesto, podría violar fácilmente el beneficio de seguridad de los tipos fantasmas si el tipo se anotara tanto como covariante como contravariante, ya que podría convertir un 'Archivo ' en un 'Archivo ', como puede observar. – kvb

+2

@kvb: ¿Cómo es eso diferente de simplemente hacer una clase base Archivo y clases derivadas "WritableFile", "LecturaFile" y "ReadableAndWritableFile"? ¿Por qué capturar algo en el sistema de tipo genérico cuando simplemente podría capturarse en el sistema de tipo ordinario? –

Cuestiones relacionadas