cuongle
cuongle

Reputation: 75326

Why covariance does not work with generic method

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

Answers (2)

Basil Kosovan
Basil Kosovan

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

alexn
alexn

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

Related Questions