2012-01-23 12 views
6

algo de código para reproducir el problema:Por qué no habrá una clase derivada de una clase abstracta con una cláusula where echó a su nivel más bajo de clase común

using System; 

public abstract class Response { } 
public abstract class Request<T> where T : Response { } 
public class LoginResponse : Response { } 
public class LoginRequest : Request<LoginResponse> { } 

public class Program 
{ 
    static void Main(string[] args) 
    { 
     LoginRequest login = new LoginRequest(); 


     /* Error: Cannot implicitly convert type 'LoginRequest' to 'Request' */ 
     Request<Response> castTest = login; 


     /* No Error */ 
     Request<LoginResponse> castTest2 = login; 
    } 
} 

Por lo que yo puedo decir a la clase LoginRequest es una Solicitud <Respuesta> porque hereda de la solicitud <T> y LoginResponse hereda de Response, entonces, ¿alguien me puede aclarar por qué obtengo el error del compilador?

nota: También he intentado una conversión explícita

Respuesta

8

Recibirá el error porque Request<Response> y Request<LoginResponse> no son covariantes.

El hecho de que LoginResponse hereda de Response no significa que Request<LoginResponse> se pueden tratar los mismos que Request<Response>. Dar a este artículo una lectura:

MSDN - Covariance and Contravariance in Generics

+0

Gracias, mi comprensión de la covarianza es un poco delgada, necesito leer más. – Robert

7

Debido a que su parámetro genérico es implícitamente invariante - los dos tipos, Request<LoginResponse> y Request<Response> son completamente distintos. C# 4.0 variación introducida en los tipos de delegado e interfaces y puede proporcionar una solución para usted aquí:

public interface IResponse<out T> where T : Response {} 

Aquí hemos declarado el tipo genérico T como Covariant.

Eric Lippert ha escrito many good blog posts sobre el tema de la varianza en C#, recomiendo leerlos.

3

LoginRequest no deriva de Request<Response>, deriva de Request<LoginResponse>.

Un tipo genérico es un tipo en sí mismo una vez compilado. La jerarquía de parámetros con plantilla es irrelevante.

7

Esto se debe a que las clases genéricas de C# no son covariantes. C# intenta evitar que haga lo siguiente:

Request<Response> castTest = login; 
castTest.Response = someOtherKindOfResponse; 

Este ejemplo es quizás más claro con las listas. Imagine si funciona lo siguiente:

var someStringList = new List<String>(); 
var someObjectList = ((List<Object>)someStringList; // This throws a compile exception, thankfully 
someObjectList.Add(1); // If the above worked, then this would compile, but would throw a runtime exception 
+0

Me gusta el ejemplo de la lista, lo hace más simple de entender. – Robert

Cuestiones relacionadas