0

I have a custom interface. I am design a function that takes an argument which is a list. When I pass an argument that is a list of a class that meets this interface, I get an error. Example code below:

class MainClass
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
        TestClass A = new TestClass();
        A.Name = "A";
        TestClass B = new TestClass();
        B.Name = "B";
        TestClassList aList = new TestClassList();

        aList.myList.Add(A);
        aList.myList.Add(B);

        PrintTestClass(aList.myList);


    }
    public static void PrintTestClass(List<ItestInterface> TestList)
    {
        foreach (ItestInterface i in TestList)
            Console.WriteLine(i.Name);
    }

}
interface ItestInterface
{
    string Name { get; set; }
}
class TestClass : ItestInterface
{
    public string Name { get; set; }
    public string otherVar { get; set; }

}
class TestClassList
{
    public List<TestClass> myList;

    public TestClassList()
    {
        myList = new List<TestClass>();
    }

}

Here, my calling of "PrintTestClass" calls an error that it cannot convert List<TestClass> to List<ItestInterface>. I try to cast it, still doesn't work. What am I doing wrong?

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
tmptplayer
  • 434
  • 7
  • 18
  • Create a 2nd class that implements `ITestInterface` and I I think you will see the problem. Every `TestClass` is a `ITestInterface` but not every `ITestInterface` has to be a `TestClass` so you can't safely put a ITestInterface in a list of TestClasses. The process of getting around this limitation is called "Covarance" and "Contravariance" – Scott Chamberlain Oct 19 '19 at 04:50
  • 1
    You can use public static void PrintTestClass(IEnumerable TestList) instead. – Xiaosu Oct 19 '19 at 05:03
  • That's not what I'm doing. I'm putting a List into a List. I'm not putting a List into a List – tmptplayer Oct 19 '19 at 05:03
  • @Xiaosu - that worked, but why? What does changing List -> IEnumerable do? – tmptplayer Oct 19 '19 at 06:02
  • 2
    @tmptplayer The `IEnumerable` interface is declared as `IEnumerable` this `out` keyword makes it "Covariant" meaning that it says that it's generic type `T` will only be used in return types (so it only comes out of the interface) therefor it's safe to cast a `List` to a `IEnumerable` (since each `TestClass` is an `ITestInterface` we're guaranteed that everything comming out of the `IEnumerable` is an `ITestInterface`. However a `List` would also allow adding of an `ITestInterface` which you can't do on a `List` –  Oct 19 '19 at 07:27
  • @Knoop - Got it, thanks. Essentially I had neglected the List write case and that the list is passed by reference not by value. – tmptplayer Oct 19 '19 at 18:07

0 Answers0