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,125
  • 19
  • 96
  • 139
  • 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
  • 47,051
  • 7
  • 96
  • 126
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
  • 95,368
  • 17
  • 122
  • 158
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
  • 77,212
  • 12
  • 152
  • 179
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,165
  • 1
  • 26
  • 41
  • 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