将IList <string>转换为IList <object>在运行时失败

zmb*_*mbq 6 c# generics

我有以下简短的C#程序:

IList<string> listString = new List<String>();
IList<object> listObject;

listObject = listString;
Run Code Online (Sandbox Code Playgroud)

这个程序不编译.最后一行导致以下编译错误:

无法将类型'System.Collections.Generic.IList'隐式转换为'System.Collections.Generic.IList'.存在显式转换(您是否错过了演员?)

所以,我添加了演员:

listObject = (IList<object>)listString;
Run Code Online (Sandbox Code Playgroud)

现在程序正确编译,但在运行时失败.的InvalidCastException升高与以下消息:

无法将类型为'System.Collections.Generic.List'1 [System.String]'的对象强制转换为'System.Collections.Generic.IList'1 [System.Object]'.

强制转换是非法的,应该被编译器捕获,或者它是合法的,不应该在运行时抛出异常.为什么行为不一致?

澄清:我不是在问为什么演员会失败.我明白为什么这样的铸造有问题.我问为什么演员阵容只在运行时失败.

Jep*_*sen 10

正如您所知,隐式转换为IList<string>to IList<object>将无法编译的原因是IList<T>接口不是协变的T.如果使用.NET 4.5,那么IReadOnlyList<out T>它可以使用它.

明确的演员之所以如此

listObject = (IList<object>)listString;
Run Code Online (Sandbox Code Playgroud)

编译,不是那个,IList<string>IList<object>以任何方式相关.这两种类型都不能分配给另一种.原因是variable(listString)的运行时类型可能是实现两个接口的类(或结构)!假设我上了这堂课:

class CrazyList : IList<string>, IList<object>  // not very smart
{
  // a lot of explicit interface implementations here
}
Run Code Online (Sandbox Code Playgroud)

然后,如果某些IList<string>碰巧是CrazyList在运行时,显式转换成功.当你编写一个显式的强制转换时,你告诉编译器"我知道这种类型可以转换为我正在投入的这种类型".由于编译器不能证明你错了,当然它相信你.

  • @zmbq由于同样的原因,您可以从_any_接口到_any_其他接口进行显式转换,例如`ICloneable cloneable = XXXX; IDisposable disposable =(IDisposable)克隆;`. (2认同)