2016-03-09 10 views
5

Walczyłem przez kowariancję i kontrrawariancję przez kilka dni i myślę, że zrozumiałem coś, ale miałem nadzieję, że mogę uzyskać potwierdzenie na tym, ponieważ nie byłem w stanie uzyskać odpowiedzi tak lub nie przez moje obecne Badania. Mam następujące klasy Hierarchia:Proszę pomóc w potwierdzeniu, czy moje rozumienie kowariancji tutaj jest poprawne?

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

} 

Wtedy, to co ja, co Zacząłem program z:

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

Teraz są dwa pytania mam:

jest następujący możliwe, ponieważ IEnumerable < T> IS kowariantna:

IEnumerable<Shape> shapesEnumerable = squares; 

I, to f ollowing nie jest możliwe, ponieważ Lista < T> nie jest kowariantna:

List<Shape> shapes = squares; 

Oto pełny kod programu, jeśli jest to wymagane do niczego:

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 
{ 

} 

Proszę mógłbyś dać mi znać, jeśli jestem na właściwy tor z tym?

+2

Tak; to jest poprawne. – SLaks

+1

@SLaks Dziękuję bardzo! – macmatthew

Odpowiedz

2

Tak, masz rację.

ten kod był niedozwolony, ponieważ możemy mieć tę trudną sytuację.

Możemy stworzyć nową klasę podobnego tys:

klasy trójkąt: Shape {}

Then

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

A teraz, jeśli w tym przypadku może być dopuszczalna

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

Możemy rozwijać się w następujący sposób:

squares.AddRange(triangles); 

lub inne problemy, takie jak to.

Kompilator Net jest bardzo mądry :)

1

To dobra sprawa kowariancji. IEnumerable<T> definiuje T jako out T, więc IEnumerable<Square> można przypisać do IEnumerable<Shape>. Powodem, dla którego nie można tego zrobić z List<T>, jest to, że nie jest to interfejs, a tylko interfejsy mogą deklarować ko- i contrawariancję.

Co więcej, nie ma sensu, aby List<T> było kowariantne, ponieważ jest ono używane jako wejście, podświetlone przykładem podanym przez Arlyoma Tonoyana. IEnumerable<T> może definiować jako taki, ponieważ jest używany tylko jako wynik.

Powiązane problemy