Search code examples
c#genericsnested-generics

C# foreach on IEnumerable<IList<object>> compiles but shouldn't


I have the following code:

IEnumerable<IList<MyClass>> myData = //...getMyData

foreach (MyClass o in myData)
{
    // do something
}

It compiles, runs and obviously I get an System.InvalidCastException.
Why does the compiler not complain? MyClass is a simple bean, no extensions.

Edit 1:
As suggested by David switching the type from IList to List the compiler complains

Edit 2:
I've understood that the behaviour is as specified in the C# Language definition. However, I don't understand why such a cast/conversion is allowed, since at runtime I always get an InvalidCastException. I opened this in order to go deeper.


Solution

  • IList<MyClass> is convertible to MyClass.

    But if you actually run it with a non-empty enumerable,

    IEnumerable<IList<MyClass>> myData = new IList<MyClass>[1] { new List<MyClass>() {new MyClass()}};
    

    You get this error:

    Unable to cast object of type 'System.Collections.Generic.List`1[MyClass]' to type 'MyClass'.

    This is in compliance with the spec:

    Section 8.8.4 The foreach statement

    ... If there is not an explicit conversion (§6.2) from T (the element type) to V (the local-variable-type in the foreach statement), an error is produced and no further steps are taken.

    ...

    There is an explicit conversion from IList<MyClass> to MyClass (though it will fail at runtime), so no error is produced.

    Section 6.2.4 Explicit reference conversions

    The explicit reference conversions are:

    • From object and dynamic to any other reference-type.
    • From any class-type S to any class-type T, provided S is a base class of T.
    • From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
    • From any interface-type S to any class-type T, provided T is not sealed or provided T implements S.

    ...