0

I have an array of Circle objects (where Circle implements IShape interface and i have a function that has a parameter of List<IShape> . . why can't i pass in my array of Circles into this ?

Visual studio gives me a build error saying can't convert List<Circle> to List<IShape>

sa_ddam213
  • 42,848
  • 7
  • 101
  • 110
leora
  • 188,729
  • 360
  • 878
  • 1,366

1 Answers1

5

The short answer is because a function Foo can be implemented like this:

void Foo(IList<IShape> c)
{
    c.Add(new Square());
}

If you passed a List<Circle> to Foo, the provided type would not be capable of storing the Square, even though the type signatures claim it is okay. IList<T> is not covariant: the general IList<Circle> cannot be an IList<IShape> because it cannot support the addition of arbitrary shapes.

The fix is to use IEnumerable<IShape> to accept arguments in Foo, but that won't work in all cases. IEnumerable<T> is covariant: the specialized IEnumerable<Circle> fits the contract of the general IEnumerable<IShape>.


This behavior is also a Good Thing. The classic example of something that is covariant when it should not be is an array. The following code will compile, but will fail at runtime:

void Bar()
{
    // legal in C#:
    object[] o = new string[10];
    // fails with ArrayTypeMismatchException: can't store Int in a String[]
    o[0] = 10;
}
Travis Gockel
  • 26,877
  • 14
  • 89
  • 116
  • Actually, `IEnumerable` will not be accepted by a method with the parameter `IEnumerable` you have to cast the collection you pass to the function to an instance of `IEnumerable` if the method signature is `Foo(IEnumerable shapes)`. – Francis R. Griffiths-Keam Mar 22 '13 at 03:53
  • 2
    @FrancisR.Griffiths-Keam, you are incorrect. As of .NET 4, IEnumerable is covariant on T, which means IEnumerable can be substituted as long as X derives from (or implements) T. – Anthony Pegram Mar 22 '13 at 04:07
  • @AnthonyPegram Ahh I missed that memo, thanks for putting the record straight. – Francis R. Griffiths-Keam Mar 22 '13 at 04:10
  • 1
    It is probably also important to note that `IList` does not have this same property (and *can't*). – Travis Gockel Mar 22 '13 at 07:21