1

I've been reading C# newbie List<Interface> question and can understand why this first example works, but not the second. Why is the first good, but the second piece of code fails to compile.

First the good code:

interface IFoo {}
class Foo : IFoo { }
class Bar : IFoo { }

        var list = new List<IFoo>();
        list.Add(new Foo());
        list.Add(new Bar());

Now for the code which introduces generics

interface IZar<TFoo> where TFoo : IFoo { }
class ZarFoo : IZar<Foo> { }
class ZarBar : IZar<Bar> { }

        var list2 = new List<IZar<IFoo>>();
        list2.Add(new ZarFoo());
        list2.Add(new ZarBar());

This is failing to compile because ZarFoo cannot be converted to IZar when surely it should be able to as it implements IZar where Foo : IFoo?

Community
  • 1
  • 1
user3791372
  • 4,445
  • 6
  • 44
  • 78

1 Answers1

4

Because IZar<TFoo> is not co-variant. You can't downcast the interface just like that.

You have to make IZar<TFoo> co-variant, by using out:

interface IZar<out TFoo> where TFoo : IFoo { }

The problem becomes clear when you create an add method:

interface IZar<TFoo> where TFoo : IFoo
{
    void Add(TFoo foo);
}
class ZarFoo : IZar<Foo>
{
    public void Add(Foo foo)
    { }
}
class ZarBar : IZar<Bar>
{
    public void Add(Bar foo)
    { }
}

If you would use the interface, you could end up adding an IFoo, where the actual type is an Foo or Bar. Returning doesn't have that problem since IFoo can be either Foo or Bar. See, there is no inheritance problem:

interface IZar<out TFoo> where TFoo : IFoo
{
    TFoo GetOne();
}
class ZarFoo : IZar<Foo>
{
    public Foo GetOne()
    { return new Foo(); }
}
class ZarBar : IZar<Bar>
{
    public Bar GetOne()
    { return new Bar(); }
}
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Great examples and illustrate the problems very well, thanks for taking the time to explain. The MSDN link is very verbose across several pages! For the short version - https://msdn.microsoft.com/en-us/library/dd997386.aspx – user3791372 May 03 '16 at 11:48