0

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; }
    }
ckv
  • 10,539
  • 20
  • 100
  • 144
  • Covariance is allowed for interfaces only. `List` is no interface. `IList` is neither co-variant nor contra-variant because you have to read and write the elements. – Nico Schertler Jun 30 '13 at 07:14
  • `List` is not what needs to be an interface. Try making Employee implement IPerson – Sam Axe Jun 30 '13 at 07:15
  • I think i have a wrong understanding on covariance. Let me see if i get some good tutorials – ckv Jun 30 '13 at 07:20

4 Answers4

4

Neither List or IList are covariants.

Try this instead:

IEnumerable<Employee> employeeList = managerList

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

haim770
  • 48,394
  • 7
  • 105
  • 133
2

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.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
0

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.

Community
  • 1
  • 1
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
0

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.

tia
  • 9,518
  • 1
  • 30
  • 44
  • Not just `IReadOnlyCollection`, there's even a [`IReadOnlyList` interface](http://msdn.microsoft.com/en-us/library/hh192385.aspx) which is covariant in its type arguement. – Jeppe Stig Nielsen Jul 01 '13 at 14:52