2011-02-18 12 views
31

¿Qué pasa con esto?T debe ser válido de forma invariable

interface IRepository<out T> where T : IBusinessEntity 
{ 
    IQueryable<T> GetAll(); 
    void Save(T t); 
    void Delete(T t); 
} 

Dice:

varianza no válido: El parámetro de tipo 'T' debe ser válida en contravariantly 'MyNamespace.IRepository.Delete (T)'. 'T' es covariante.

+1

¿Qué terminaste haciendo? Estoy enfrentando el mismo problema. Las respuestas realmente no lo resuelven; Necesito GetAll, Guardar y Eliminar en la misma clase – David

+1

Lo siento, no recuerdo. Fue hace 4 años. – Eduardo

Respuesta

55

Considérese lo que sucedería si el compilador permitió que:

interface IR<out T> 
{ 
    void D(T t); 
} 

class C : IR<Mammal> 
{ 
    public void D(Mammal m) 
    { 
     m.GrowHair(); 
    } 
} 
... 
IR<Animal> x = new C(); 
// legal because T is covariant and Mammal is convertible to Animal 
x.D(new Fish()); // legal because IR<Animal>.D takes an Animal 

Y usted acaba de intentar hacer crecer el cabello en un pescado.

"salir" significa que "T solo se usa en las posiciones de salida". Lo estás usando en una posición de entrada.

+7

Nunca podría entender por qué cuando se explica algo, cómo 'T' y' IR' y 'C' y' x' son nombres de variable válidos. Esto también se aplica a la documentación de MSDN, especialmente con genéricos. ¿Qué es "D"? – David

+6

@David: Son válidos porque cumplen los criterios para los identificadores en la especificación C#, pero creo que significa pedagógicamente válido. La pedagogía del uso de nombres cortos es recordar sutilmente al lector que este es un ejemplo general, ampliamente aplicable, en el que deberían pensar en abstracto, y no una solución a un problema específico en un dominio específico. –

+0

Una vez crecí pelo en un pez. Fue un momento interesante en mi vida. – bubbleking

19

Los dos métodos siguientes se equivocan:

void Save(T t); 
void Delete(T t); 

No se puede tener como argumento T método. Solo como tipo de devolución si desea que sea covariante (out T) en su definición genérica.

O si desea contravarianza entonces usted podría utilizar el parámetro genérico sólo como argumento de método y no el tipo de devolución:

interface IRepository<in T> where T : IBusinessEntity 
{ 
    void Save(T t); 
    void Delete(T t); 
} 
+0

Respuesta completa y limpia. Gracias –

37

puede utilizar un parámetro de tipo out única contravariantly, es decir, en el tipo de retorno. Por lo tanto, IQueryable<T> GetAll() es correcto, pero void Delete(T t) no lo es.

Desde T se utiliza tanto co- y contravariantly en su clase, no se puede utilizar out aquí (ni in).

Aquí hay un poco de historia: Covariance and Contravariance (Wikipedia).

+10

Tenga en cuenta que * puede * estar en los parámetros, pero solo con algo así como 'Acción ' que invierte la dirección nuevamente. –

Cuestiones relacionadas