我有以下内容:
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,而编译器无法确定这一点。
答案 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
列表。