ForEach在运行时提供Invalid Cast

时间:2011-02-18 11:05:21

标签: c# linq types foreach

我有以下内容:

 foreach (ItemOption itemOption in p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id))
  { // do some work on itemoptions }

这个编译。 但是在运行时我得到一个Invalid Cast异常:

  

无法将“Grouping [System.String,MyNameSpace.ItemOption]”类型的对象强制转换为“MyNameSpace.ItemOption”。

如果我将代码更改为,例如一个String作为项目的类型:

 foreach (String itemOption in p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id))
  { // do some work on itemoptions }

然后编译器告诉我类型不兼容。

为什么编译器不会在第一个代码块中标记类型不兼容?


我做了一些进一步的调查,并发现,给出以下代码:

var foo = p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id));
Type singleElementType = foo.ElementAt(0).GetType();

singleElementType是:

  

System.Linq.Lookup`2 +分组[System.String,MyNamespace.ItemOption]


更新 根据答案,我将一个更简单的案例放在一起来证明问题

给出对象:

interface IMyObj
{
    string Id;
}

class MyObj : IMyObj
{
    public string Id;
    public MyObj2 cg;
}

class MyObj2
{
}

这将在编译时失败

IEnumerable<MyObj> compileTimeFailList = new List<MyObj>()
foreach (MyObj2 myObj2 in compileTimeFailList.Where(x => x.Id != null))
{

这将在运行时失败

IEnumerable<IMyObj> runtimeFailList = new List<IMyObj>();
foreach (MyObj2 myObj2 in runtimeFailList.Where(x => x.Id != null))
{ 

原因是runtimeFailList中的对象可能会扩展MyObj2,而编译器无法确定这一点。

3 个答案:

答案 0 :(得分:3)

ItemOption可能不是一个密封的类(与System.String不同),因此p.Items.Select(...).GroupBy(...)的结果可能是IGrouping<...>的实现,也是 ItemOption值。编译器无法知道,因此它会插入一个隐式转换。由于string未实现IGrouping<...>并且已被密封,编译器可以发现这绝对是一个错误。

foreach 总是在必要时包含演员。这有点令人讨厌,因为它是隐藏的...但没有它,foreach使用pre-generics会非常痛苦。

现在,为什么实际错误...结果中的每个项目都将是一个分组而不是一个单独的项目。如果您需要更多帮助来处理结果,请与我们联系。

答案 1 :(得分:0)

因为类String不能被继承,但是你的类ItemOption可以被继承,也可以隐式地进行。

答案 2 :(得分:0)

关于演员阵容失败的原因:

foreach (ItemOption itemOption in p.Items.Select(e => e.ItemOption).GroupBy(e => e.Id))

您的.GroupBy未返回由ID捆绑的ItemOptions列表。而是返回列表列表:第一个列表包含所有单独的Id,并且每个Id都有一个具有相同Id的ItemOption列表。