2016-03-09 17 views
5

Tôi đã chiến đấu thông qua hiệp phương sai và đối nghịch trong một vài ngày và tôi nghĩ rằng tôi đã hiểu điều gì đó nhưng tôi hy vọng rằng tôi có thể nhận được xác nhận về điều này vì tôi không thể nhận được câu trả lời có hoặc không thông qua hiện tại của mình nghiên cứu. Tôi có hệ thống phân cấp lớp sau:Vui lòng hỗ trợ xác nhận xem sự hiểu biết của tôi về hiệp phương sai ở đây có đúng không?

class Shape 
{ 
    public string Name { get; set; } 
} 
class Square : Shape 
{ 

} 

Sau đó, đây là những gì tôi những gì tôi đang bắt đầu chương trình với:

List<Square> squares = new List<Square>() { new Square { Name = "Square One" }, new Square { Name = "Square Two" } }; 
IEnumerable<Square> squaresEnum = squares; 

Bây giờ là hai câu hỏi tôi có:

Sản phẩm sau có thể vì IEnumerable < T> IS covariant:

IEnumerable<Shape> shapesEnumerable = squares; 

AND, là f ollowing KHÔNG thể vì Danh sách < T> là KHÔNG hiệp biến:

List<Shape> shapes = squares; 

Đây là mã chương trình đầy đủ nếu nó là cần thiết cho bất cứ điều gì:

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<Square> squares = new List<Square>() { new Square { Name = "Square One" }, new Square { Name = "Square Two" } }; 
     IEnumerable<Square> squaresEnum = squares; 

     /* Does this work because IEnumerable<T> is covariant? */ 
     IEnumerable<Shape> shapesEnumerable = squares; 

     /* Does this NOT work because List<T> is NOT covariant */ 
     //List<Shape> shapes = squares; 

     Console.ReadKey(); 
    } 
} 
class Shape 
{ 
    public string Name { get; set; } 
} 
class Square : Shape 
{ 

} 

Xin bạn có thể cho tôi biết nếu tôi đang trên theo dõi đúng với điều này?

+2

Có; đúng rồi. – SLaks

+1

@SLaks Cảm ơn bạn rất nhiều! – macmatthew

Trả lời

2

Có, bạn đang đi đúng hướng.

mã này không được phép, vì chúng tôi có thể gặp phải tình huống khó khăn này.

Chúng ta có thể tạo lớp mới như ths:

lớp Triangle: Shape {}

Sau đó

IEnumerable<Shape> triangles = new List<Triangle>() 
{ 
     new Triangle { Name = "Triangle One" }, 
     new Triangle { Name = "Triangle Two" } 
}; 

Và bây giờ nếu trường hợp này có thể được cho phép

List<Shape> squares = new List<Square> { ... }; 

Chúng tôi có thể phát triển như thế này

squares.AddRange(triangles); 

hoặc các vấn đề khác như thế này.

Trình biên dịch Net rất thông minh :)

1

Đây là trường hợp tốt về hiệp phương sai. IEnumerable<T> xác định Tout T, vì vậy, IEnumerable<Square> có thể được gán cho IEnumerable<Shape>. Lý do bạn không thể làm điều này với List<T> là nó không phải là một giao diện, và chỉ có giao diện mới có thể khai báo đồng và contravariance.

Ngoài ra, nó không có ý nghĩa đối với List<T> để có T là biến thể, vì nó cũng được sử dụng làm đầu vào, được đánh dấu bằng ví dụ do Arlyom Tonoyan đưa ra. IEnumerable<T> có thể xác định như vậy vì nó chỉ được sử dụng làm đầu ra.

Các vấn đề liên quan