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.
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.
...