Reputation: 75326
Assume I have interface and class:
public interface ITree {}
public class Tree : ITree {}
As IEnumerable<T>
is covariant, the code line below is compiled successfully:
IEnumerable<ITree> trees = new List<Tree>();
But when I put it into generic method:
public void Do<T>() where T : ITree
{
IEnumerable<ITree> trees = new List<T>();
}
I get compiled error from compiler:
Error 1 Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?) D:\lab\Lab.General\Lab.General\Program.cs 83 40 Lab.General
Why covariance does not work in this case?
Upvotes: 30
Views: 2960
Reputation: 1069
I just want to add more examples:
You can call MakeDesignWhereTIsReference
and pass VehicleStruct
as T
. But the problem is that:
Covariance and contravariance are supported for reference types, but they are not supported for value types. From MS doc
So we also need to limit T
to be a reference type; It may be done with the help of the class
keyword that adds a restriction we need.
public static class TestCovariance
{
public static void MakeDesignWhereTIsReference<T>()
where T : class, IVehicle // pay attention to class restriction
{
ICollection<IDesign<IVehicle>> list = new List<IDesign<IVehicle>>();
var design = new Design<T>();
list.Add(design);
}
public static void MakeDesignWhereTIsStruct<T>()
where T : struct, IVehicle //This method will throw a cast exception
{
ICollection<IDesign<IVehicle>> list = new List<IDesign<IVehicle>>();
var design = new Design<T>();
list.Add((IDesign<IVehicle>)design);
}
}
public struct VehicleStruct : IVehicle { }
TestCovariance.MakeDesignWhereTIsReference<Ship>();
TestCovariance.MakeDesignWhereTIsStruct<VehicleStruct>();
Upvotes: 0
Reputation: 59002
That is because variance only works with reference types (classes, interfaces & delegates). Add a class constraint and it compiles just fine:
public static void Do<T>() where T : class, ITree
Upvotes: 34