Please help confirm if I understand covariance correctly?

I fought through covariance and contravariance for several days, and I think I understood something, but I was hoping I could get confirmation of this, because I could not get the answer β€œyes” or β€œno” through my Current study. I have the following class hierarchy:

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

Then, here is what I started with the program:

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

Now I have two questions:

Is the following possible, because IEnumerable <T> IS is covariant:

 IEnumerable<Shape> shapesEnumerable = squares; 

And, the following is NOT possible, since List <T> is NOT covariant:

 List<Shape> shapes = squares; 

Here is the complete code, if needed for anything:

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

Please, could you tell me if I am on the right track?

+5
source share
2 answers

Yes you are right.

this code is not valid because we can have this difficult situation.

We can create a new class, for example ths:

class Triangle: Shape {}

Then

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

And now, if this case is valid

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

We can grow like that

 squares.AddRange(triangles); 

or other similar problems.

Net compiler is very smart :)

+2
source

This is a good case of covariance. IEnumerable<T> defines T as out T , so IEnumerable<Shape> can be assigned IEnumerable<Square> . The reason you cannot do this with List<T> is because it is not an interface, and only interfaces can declare joint and contravariance.

In addition, it does not make sense for List<T> have covariance T , since it is also used as an input signal, highlighted by the example given by Arly Tonoyan. IEnumerable<T> can define as such, since it is used only as an output.

+1
source

Source: https://habr.com/ru/post/1244707/


All Articles