Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Please assist in confirming if my understanding of covariance here is correct?

Tags:

c#

oop

I have been battling through covariance and contravariance for a few days now and I think I have understood something but I was hoping that I could get confirmation on this as I haven't been able to get a yes or no answer through my current research. I have the following class hierarchy:

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

}

Then, this is what I what I started off the program with:

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

Now are the two questions I have:

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

IEnumerable<Shape> shapesEnumerable = squares;

AND, is the following NOT possible because List< T > is NOT covariant:

List<Shape> shapes = squares;

Here is the full program code if it is required 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 let me know if I'm on the right track with this?

like image 476
macmatthew Avatar asked Sep 26 '22 03:09

macmatthew


2 Answers

Yes, you are right track.

this code was not permissible, because we can have this difficulte situation.

We can create new class like 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 can be permissible

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

We can develop like this

squares.AddRange(triangles);

or other issues like this.

The Net compiler is very clever :)

like image 51
Artyom Tonoyan Avatar answered Sep 27 '22 18:09

Artyom Tonoyan


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

Also, it does not make sense for List<T> to have T be covariant, as it is also used as an input, highlighted by the example given by Arlyom Tonoyan. IEnumerable<T> can define at as such since it is only used as output.

like image 22
juunas Avatar answered Sep 27 '22 17:09

juunas