繁体   English   中英

C#; InvalidCastException,怎么了?

[英]C#; InvalidCastException, what´s wrong?

我想将列表的对象转换为它的子类。 为此,我使用Casting 填充 List<BaseClass> 到 List<ChildClass>

现在,当我执行代码时,我总是在 System.Core.dll 中得到一个 InvalidCastException ""The Object Item cannot be cast to 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,我无法在那里更改任何内容。 项目继承自 IEquatable。

LINQ 肯定可以正常工作,但是当我投射时出现错误。 我做错了什么?

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

如果一项或多项不属于泛型参数中指定的类型,则在调用Cast时将发生InvalidCastException 请参阅 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类型。 这解释了异常。

...说列表由项目组成,这就是为什么我想将它们向下转换为子项目。

您在问题中发布的继承层次结构是System.Object -> Item -> SubItem 我包括 Object ,因为我假设我们正在处理引用类型,并且所有东西最终都继承自 System.Object )。 这意味着SubItem可以转换为ItemSystem.ObjectItem实例可以转换为System.Object 然而,逆是不正确的,你不能投出图表。 System.Object的实例不能成为Item并且Item不能成为SubItem

拥有一个通用的List<Item>很好,它可以包含类型SubItemItem或任何派生自Item东西。 但同样,您不能将Item的实例转换为SubItem

如果这还不清楚,那么我建议您阅读有关继承和多态的一些内容,这是一个不同的主题,但如果您想知道为什么使用继承以及是什么使它成为如此出色的抽象工具,这也非常重要。

可能是您列表中的某些项目不是派生类类型,您应该能够在调试器中看到这一点。 另外,正如有人指出的那样,您可能必须在进行转换之前从数据库中取回数据,因此 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();

假设 Inventory 包含一个“Item”列表,并且您想获得一个“SubItem”列表,将您的行替换为:

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

因此,第一部分将为您提供符合您条件的项目,第二部分将为每个项目创建一个新的子项目并为您提供它们的列表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM