2012-04-27 15 views
14

tengo las siguientes clases/interfaces:implementación de interfaces genéricos anidados

// Model 
public class A : IA { } 
// ModelLogic 
public class B : IB<A> { } 

// Model Interface 
public interface IA { } 
// ModelLogic Interface 
public interface IB<T> where T : IA { } 

intento crear una nueva instancia utilizando el siguiente código:

IB<IA> foo = new B(); 

estoy consiguiendo el error siguiente:

Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?) 

¿Puede alguien explicar por qué esto no es posible?

+0

¿Qué versión de C# estás usando? – Oded

+3

[Preguntas frecuentes sobre covarianza y contradicción] (http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx) y [esta serie de blogs] (http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/) por Eric Lippert – Oded

+1

Respuesta

41

OK, vamos a reemplazar con AFish, IA con IAnimal, B con Aquarium, y IB<T> con IContainer<T>. Y lo añadiremos un miembro de IContainer<T>, y una segunda aplicación de IAnimal:

// Model 
public class Fish : IAnimal { } 
public class Tiger : IAnimal { } 
// ModelLogic 
public class Aquarium : IContainer<Fish> 
{ 
    public Fish Contents { get; set; } 
} 

// Model Interface 
public interface IAnimal { } 
// ModelLogic Interface 
public interface IContainer<T> where T : IAnimal 
{ 
    T Contents { get; set; } 
} 

IContainer<IAnimal> foo = new Aquarium(); // Why is this illegal? 
foo.Contents = new Tiger(); // Because this is legal! 

se puede poner un tigre en foo - foo se escribe como un contenedor que puede contener cualquier animal. Pero solo puedes poner un pez en un acuario. Dado que las operaciones que puede realizar legalmente en un Aquarium son diferentes que las operaciones que puede realizar en un IContainer<IAnimal>, los tipos no son compatibles.

la función que desea se llama genérica covarianza interfaz y es apoyado por C# 4, pero hay que demostrar al compilador que nunca se va a poner un tigre en su tanque de peces. Lo que se quiere hacer es:

// Model 
public class A : IA { } 
// ModelLogic 
public class B : IB<A> { } 

// Model Interface 
public interface IA { } 
// ModelLogic Interface 
public interface IB<out T> where T : IA { } 

Aviso la anotación de covarianza en IB. Esto out significa que T solo se puede usar como salida, no como entrada. Si T es solo una salida, entonces no hay forma de que alguien coloque un tigre en esa pecera porque no hay una propiedad o método de "ponerlo en" posible.

Escribí una serie de artículos de blog mientras agregamos esa característica a C#; si usted está interesado en las consideraciones de diseño que entraron en la función, consulte:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

+0

Varianza no válida: el parámetro de tipo 'T' debe ser invariablemente válido en 'xx.IContainer .Contents'. 'T' es covariante. \t Recibo este error. Soy nuevo en cosas covariantes. ¿Qué significa el error? – Sandeep

+3

@Sandeep: de alguna manera estás usando T en una posición de entrada cuando has dicho que solo vas a usarlo en una posición de salida. ¿'Contents' es una propiedad con un setter? Si es así, entonces claramente se está utilizando T en una posición de entrada, y por lo tanto la interfaz no se puede hacer covariante en T. –

+0

Gracias Eric. Eso lo resolvió – Sandeep

1

para fijar su código, basta con cambiar

public interface IB<T> where T : IA { } 

a

public interface IB<out T> where T : IA { } 
+0

awww, Eric me ganó :) – CodingWithSpike

0

No es fácil para ver cuando tienes interfaces vacías.Considere usted tiene un método M en la interfaz IB:

public interface IB<T> where T : IA 
{ 
    void M(T t); 
} 

Y aquí es la implementación de B:

public class B : IB<A> 
{ 
    public void M(A t) 
    { 
     // only object of type A accepted 
    } 
} 

Entonces usted tiene objeto C, que también implementa IA:

public class C : IA { } 

Así , si su código sería posible, puede llamar al:

IB<IA> foo = new B(); 
foo.M(new C()); 

El problema es que la clase B solo acepta objetos del tipo A. ¡Error!

Cuestiones relacionadas