ckv
ckv

Reputation: 10830

Covariance in C# compile error

Why does the below code throw compile error? As per C# 4.0 Covariance should'nt such a conversion be allowed. List employeeList = managerList;

class Program
    {
        static void Main(string[] args)
        {
            List<Manager> managerList = new List<Manager>()
            {
                new Manager{ FirstName="ASFD", LastName="DSS", NoOfReportees=4},
                new Manager{ FirstName="rrr", LastName="dsasde", NoOfReportees=22}
            };
            List<Employee> employeeList = managerList;
        }
    }
    public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    public class Manager:Employee
    {
        public int NoOfReportees { get; set; }
    }

Upvotes: 0

Views: 185

Answers (4)

Rohit Vats
Rohit Vats

Reputation: 81253

List<T> is invariant. You need IEnumerable<T> which is covariant.

Refer to the explanation here by Eric Lippert explained so nicely with zoo analogy -

A List<Mammal> cannot be converted to a List<Animal> because you can put a lizard into a list of animals. A List<Mammal> cannot be converted to a List<Giraffe> because there might be a tiger in the list already.

Therefore List<T> has to be invariant in T.

However, List<Mammal> can be converted to IEnumerable<Animal> (as of C# 4.0) because there is no method on IEnumerable<Animal> that adds a lizard. IEnumerable<T> is covariant in T.

Upvotes: 0

tia
tia

Reputation: 9698

Covariant interface must be declared explicitly using out keyword. If you are using .Net 4.5, there is IReadOnlyCollection<T> interface

IReadOnlyCollection<Employee> employeeList = managerList;

Noted that it is read-only, which is logical because we can read Employee from List<Manager> but we cannot add Employee to it.

Upvotes: 0

JLRishe
JLRishe

Reputation: 101728

Think about it this way: If the assignment were allowed, you could do this:

List<Manager> managerList = new List<Manager>()
{
    new Manager{ FirstName="ASFD", LastName="DSS", NoOfReportees=4},
    new Manager{ FirstName="rrr", LastName="dsasde", NoOfReportees=22}
};
List<Employee> employeeList = managerList;
employeeList.Add(new Employee{ FirstName = "John", LastName = "Doe"});

and now your managerList would contain an item that was not a Manager, violating the constraints of the list.

If it would suit your needs, you can, however, do this:

List<Employee> employeeList = new List<Employee>(managerList);

because it doesn't violate the original list.

Upvotes: 2

haim770
haim770

Reputation: 49105

Neither List or IList are covariants.

Try this instead:

IEnumerable<Employee> employeeList = managerList

More information on MSDN: Covariance and Contravariance (C# and Visual Basic)

Upvotes: 4

Related Questions