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?
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 :)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With