2012-01-23 11 views
6

Một số mã để tái tạo vấn đề:Tại sao không phải là một lớp được thừa kế từ một lớp trừu tượng với một mệnh đề where đúc đến lớp chung thấp nhất

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; 
    } 
} 

Như xa như tôi có thể nói với lớp LoginRequest là một yêu cầu < Phản hồi > vì được kế thừa từ Yêu cầu <T> và LoginResponse kế thừa từ Phản hồi để mọi người có thể khai sáng cho tôi biết tại sao tôi gặp lỗi trình biên dịch?

lưu ý: tôi cũng đã cố gắng chuyển kiểu tường minh

Trả lời

8

Bạn nhận được lỗi vì Request<Response>Request<LoginResponse> không phải là biến thể.

Chỉ vì LoginResponse kế thừa từ Response không có nghĩa là Request<LoginResponse> có thể được coi là giống như Request<Response>. Cho bài viết này đọc:

MSDN - Covariance and Contravariance in Generics

+0

Xin cảm ơn, sự hiểu biết về hiệp phương sai của tôi hơi cần phải đọc nhiều hơn. – Robert

7

Bởi vì thông số chung của bạn là mặc nhiên bất biến - hai loại, Request<LoginResponse>Request<Response> là hoàn toàn khác biệt. C# 4.0 sai giới thiệu trong các loại đại biểu và các giao diện và có thể cung cấp một giải pháp cho bạn đây:

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

Ở đây chúng ta đã tuyên bố kiểu generic T như Covariant.

Eric Lippert đã viết many good blog posts về chủ đề phương sai trong C#, tôi khuyên bạn nên đọc chúng.

3

LoginRequest không xuất phát từ Request<Response>, nó xuất phát từ Request<LoginResponse>.

Loại chung là một loại trong chính nó sau khi được biên dịch. Phân cấp tham số templated là không liên quan.

7

Điều này là do các lớp chung C# không phải là biến thể. C# đang cố gắng ngăn bạn thực hiện những việc sau:

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

Ví dụ này có lẽ rõ ràng hơn với Danh sách. Hãy tưởng tượng nếu những điều sau đây hoạt động:

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

Tôi thích ví dụ về danh sách nó làm cho nó dễ hiểu hơn. – Robert