C#; InvalidCastException,出错了什么?

时间:2016-04-18 19:01:52

标签: c# linq exception

我想将列表的对象强制转换为它的子类。 为此,我使用了Casting populated List<BaseClass> to List<ChildClass>

现在,当我执行代码时,我总是在System.Core.dll中获得InvalidCastException“”对象项不能转换为SubItem“

[Serializable]
public class SubItem: Item
{
    public SubItem(int id) : base( id)
    {          
    }
}


public getStuff(int id){
 //where the Error is thrown
//Inventory has Items in it, furthermore atm Inventory is definitely not     empty, but could be later on
 var items = Inventory.FindAll(x=> x.id==id).Cast<SubItem>().ToList();
}

项目来自API,我无法更改任何内容。 Item继承自IEquatable。

LINQ肯定有效,但是当我正在投射时,我得到错误。我做错了什么?

3 个答案:

答案 0 :(得分:1)

我将假设您的属性Inventory是泛型类型Item的强类型集合/列表/ IEnumerable(例如:ICollection<Item>)。

如果一个或多个项目不是泛型参数中指定的类型,则在调用InvalidCastException时将发生Cast。请参阅Microsoft页面Enumerable.Cast中的详细信息。为了解决这个问题,您只需要检索那些将在过滤器中执行强制转换的类型的项目。这可以使用Enumerable.OfType完成。然后你的代码变成:

var items = Inventory.FindAll(x=> x.id==id).OfType<SubItem>().ToList();

来自文档Enumerable.Cast

  

如果无法将元素强制转换为类型TResult,则此方法将抛出异常。要仅获取可以强制转换为TResult类型的元素,请使用OfType方法而不是Cast(IEnumerable)。

根据这些评论进行修改

确定所有返回的项目都是Item类型,而不是SubItem。这解释了例外。

  

...说List包含Item,这就是为什么我要将它们转发给SubItem。

您在问题中发布的继承层次结构是System.Object - &gt; Item - &gt; SubItem。 (我包含Object,因为我假设我们正在处理引用类型,并且最终所有内容都继承自System.Object )。这意味着可以将SubItem转换为ItemSystem.ObjectItem实例可以转换为System.Object。然而反之则不然,你不能抛出图表。 System.Object的实例无法成为ItemItem无法成为SubItem

拥有通用List<Item>很好,这可能包含SubItemItem类型或从Item派生的任何内容。但同样,您无法将Item的实例投射到SubItem

如果这个不清楚,那么我建议你做一些关于继承和多态性的阅读,这是一个不同的主题,但如果你想知道为什么使用继承以及是什么使它成为一个很好的抽象工具的原因也非常重要

答案 1 :(得分:1)

可能是列表中的某些项不是派生类类型,您应该能够在调试器中看到它。此外,正如有人指出你可能必须在进行演员之前从数据库中取回数据,linq提供商可能无法为你做这件事。

所以你可以尝试以下任何一种方法:

  • 过滤掉不属于SubItem的项目
var items = Inventory.FindAll(x=> x.id==id).OfType<SubItem>().ToList();
  • 在投射
  • 之前从数据库中拉回数据
var items = Inventory.FindAll(x=> x.id==id).ToList().Cast<SubItem>().ToList();
  • 如果linq提供程序无法执行OfType
  • ,则两者的组合
var items = Inventory.FindAll(x=> x.id==id).ToList().OfType<SubItem>().ToList();

答案 2 :(得分:0)

假设Inventory包含一个“Item”列表,并且您想获得一个“SubItem”列表,请用以下内容替换您的行:

var items = Inventory.Where(x => x.id == id).Select(x => new SubItem(x.id)).ToList();

所以第一部分将为您提供符合条件的项目,第二部分将为每个项目创建一个新的SubItem,并为您提供一个列表。