0

When I have a class Car that implements ICar and I have a List<Car> why is it possible to call a method expecting IEnumerable<ICar> but neither IList<ICar> nor List<ICar>?

IList<T> is derived from IEnumerable<T> and List<T> implements IEnumerable<T>.

So if I can assign List<Car> to an IEnumerable<ICar> because the compiler figures out that Car is an ICar why doesn't it work further down the inheritance / implementation chain?

using System.Collections.Generic;

internal class Program
{
    private static void Main()
    {
        var fords = new List<Ford>() { new Ford("T") };

        IEnumerableOfICar(fords);
        IListOfICar(fords); //error CS1503: Argument 1: cannot convert from 'List<Ford>' to 'IList<ICar>'
        ListOfICar(fords); //error CS1503
        IEnumerableOfCar(fords);
        IListOfCar(fords); //error CS1503
        ListOfCar(fords); //error CS1503
        IEnumerableOfFord(fords);
        IListOfFord(fords);
        ListOfFord(fords);
    }

    private static void IEnumerableOfICar(IEnumerable<ICar> cars)
    {
        foreach (var car in cars)
        {
            System.Console.WriteLine(car.Model);
        }
    }

    private static void IListOfICar(IList<ICar> cars)
    {
        IEnumerableOfICar(cars);
    }

    private static void ListOfICar(List<ICar> cars)
    {
        IEnumerableOfICar(cars);
    }

    private static void IEnumerableOfCar(IEnumerable<Car> cars)
    {
        IEnumerableOfICar(cars);
    }

    private static void IListOfCar(IList<Car> cars)
    {
        IEnumerableOfICar(cars);
        IListOfICar(cars); //error CS1503
        ListOfICar(cars); //error CS1503
    }

    private static void ListOfCar(List<Car> cars)
    {
        IEnumerableOfICar(cars);
        IListOfICar(cars); //error CS1503
        ListOfICar(cars); //error CS1503
    }

    private static void IEnumerableOfFord(IEnumerable<Ford> cars)
    {
        IEnumerableOfICar(cars);
        IEnumerableOfCar(cars);
    }

    private static void IListOfFord(IList<Ford> fords)
    {
        IEnumerableOfICar(fords);
        IEnumerableOfCar(fords);
        IListOfICar(fords); //error CS1503
        IListOfCar(fords); //error CS1503
    }

    private static void ListOfFord(List<Ford> fords)
    {
        IEnumerableOfICar(fords);
        IEnumerableOfCar(fords);
        IListOfICar(fords); //error CS1503
        ListOfICar(fords); //error CS1503
        IListOfCar(fords); //error CS1503
        ListOfCar(fords); //error CS1503
    }
}

internal interface ICar
{
    string Model { get; }
}

internal abstract class Car : ICar
{
    public string Model { get; }

    protected Car(string model) => this.Model = model;
}

internal class Ford : Car
{
    public Ford(string model) : base(model) { }
}
Dee J. Doena
  • 1,631
  • 3
  • 16
  • 26
  • 6
    `IEnumerable` is covariant because it only produces data. `IList` is invariant because you can both get data out and also put new data in. – Ben Voigt Jul 14 '21 at 17:05
  • 3
    imagine that you have `abstract class Sedan : ICar` and also `abstract class Convertible : ICar`. You can put a `Corolla` into a `List` and into a `List` but not into a `List`. That means `List` is not compatible with `List`. – Ben Voigt Jul 14 '21 at 17:08

0 Answers0