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

时间:2013-07-08 08:12:34

标签: c# generics

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

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

listObject = listString;

此程序无法编译。最后一行导致以下编译错误:

  

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

所以,我添加了演员:

listObject = (IList<object>)listString;

现在程序正确编译,但在运行时失败。引发InvalidCastException,并显示以下消息:

  

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

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

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

5 个答案:

答案 0 :(得分:10)

IList<string>IList<object>的隐式强制转换无法编译的原因是,您似乎知道,IList<T>接口 不是< {em> T中的协变。如果使用.NET 4.5,则使用IReadOnlyList<out T>代替它,它将起作用。

显式转换的原因

listObject = (IList<object>)listString;

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

class CrazyList : IList<string>, IList<object>  // not very smart
{
  // a lot of explicit interface implementations here
}

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

答案 1 :(得分:4)

将字符串列表提供给对象列表的一种方法是:

IList<object> objects = listOfStrings.Cast<Object>().ToList();

请注意,最好是代码的可维护性限制此类强制转换,并在需要时对它们进行非常明确的说明,如果原因则用注释标记它们 转换的背后并不是很明显。

编辑:一个重要的注意事项是,上面的代码实际上并没有将一种类型的列表转换为另一种类型。相反,它将初始列表的各个成员转换为另一种类型,然后.ToList()方法创建一个包含转换对象的单独列表。

第二次编辑:实际上,没有任何评论问题可以充分解释问题。请查看John Skeet的回答here。显式强制转换在编译时不会失败,因为编译器期望它在某些时候会遇到显式强制转换的实现,而使用泛型IList<T>接口的协变赋值将失败,因为它不受支持

答案 2 :(得分:2)


listObject.Add(10); // ok
string s = listString[0]; // WTF?!!!

由于IList可变性,这种转换毫无意义。

答案 3 :(得分:1)

您可以通过Collection Initializer执行此操作。以下代码片段适用于我。

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

listObject = new List<object>(listString);

答案 4 :(得分:1)

如果您无法访问基础List

IList<object> listObject = listString.Cast<object>().ToList();

如果您可以访问基础List

Ilist<object> listobject = (new List<string>()).ConvertAll(s => (object)s);