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
toList
produces the compile-time error. Also, while it's stillIList
, doing this produces the compile-time error:MyClass x = myData.First();
– NewburgMyClass
and also implementsIList<MyClass>
. The compiler does not check what you assign, it checks the declared type on the left side. The code would be perfectly valid if you'd assignnew List<MyClassChild>()
andMyClassChild
was a child and implementedIList<MyClass>
. – Oskarforeach
that would still require a downcast though. That is, it's not legal to writeMyClass foo = myData.GetEnumerator().Current;
- it would need an explicit cast toMyClass
. Downcasts aren't usually implicit. So the question remains whyforeach
inserts such a cast automatically. I assume the answer is so users were able to writeforeach (MyType x in myUntypedList)
in the days before generics. – Sarahforeach
always had a builtin explicit cast, they can enumerateList<Object>
and cast to whatever you specify in the loop variable-type. That will fail at runtime. Of course the reason is that theforeach
is much older than generics. – Oskar