I have the following short C# program:
IList<string> listString = new List<String>();
IList<object> listObject;
listObject = listString;
This program doesn't compile. The last line causes the following compilation error:
Cannot implicitly convert type 'System.Collections.Generic.IList' to 'System.Collections.Generic.IList'.
An explicit conversion exists (are you missing a cast?)
So, I've added the cast:
listObject = (IList<object>)listString;
Now the program compiles properly, but fails at runtime. An InvalidCastException
is raised with the following message:
Unable to cast object of type 'System.Collections.Generic.List'1[System.String]' to type 'System.Collections.Generic.IList'1[System.Object]'.
Either the cast is illegal and should be caught by the compiler, or it is legal and shouldn't throw an exception at runtime. Why the inconsistent behavior?
CLARIFICATION: I am not asking why the cast fails. I understand why such casting is problematic. I am asking why the cast fails only at runtime.
Best Answer
The reason why the implicit cast from
IList<string>
toIList<object>
won't compile is, as you seem to know, that theIList<T>
interface is not covariant inT
. If, with .NET 4.5, you usedIReadOnlyList<out T>
instead, it would work.The reason why the explicit cast
will compile, is not that
IList<string>
andIList<object>
are related in any way. Neither type is assignable to the other. The reason is that the runtime type of your variable (listString
) might be a class (or struct) which implemented both interfaces! Suppose I made this class:Then if some
IList<string>
happened to be aCrazyList
at runtime, the explicit cast would succeed. When you write an explicit cast, you're telling the compiler "I know the type is going to be convertible to this type I'm casting into". Since the compiler can't prove you're wrong, of course it believes you.