简体   繁体   English

C#; InvalidCastException,怎么了?

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

I want to cast the Objects of an List to it´s Subclass.我想将列表的对象转换为它的子类。 For that I used Casting populated List<BaseClass> to List<ChildClass>为此,我使用Casting 填充 List<BaseClass> 到 List<ChildClass>

Now, when I execute the Code I always get an InvalidCastException in System.Core.dll ""The Object Item cannot be cast to SubItem "现在,当我执行代码时,我总是在 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();
}

Item is from an API, I am not able to change anything there.项目来自 API,我无法在那里更改任何内容。 Item inherits from IEquatable.项目继承自 IEquatable。

The LINQ is definitely working, but when I am casting I get the Error. LINQ 肯定可以正常工作,但是当我投射时出现错误。 What do i do wrong?我做错了什么?

I am going to assume that your property Inventory is strongly typed collection/list/IEnumerable of generic type Item (example: ICollection<Item> ).我将假设您的财产Inventory是泛型类型Item (例如: ICollection<Item> )的强类型集合/列表/IEnumerable。

The InvalidCastException will occur when calling Cast if one or more items is not of the type specified in the generic argument.如果一项或多项不属于泛型参数中指定的类型,则在调用Cast时将发生InvalidCastException See details in the Microsoft page Enumerable.Cast .请参阅 Microsoft 页面Enumerable.Cast中的详细信息。 To get around that you need to only retrieve items of that type which will execute the cast on them during the filter.为了解决这个问题,您只需要检索该类型的项目,这些项目将在过滤器期间对它们执行强制转换。 This can be done with Enumerable.OfType .这可以通过Enumerable.OfType来完成。 Your code then becomes:然后您的代码变为:

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

From the documentation Enumerable.Cast从文档Enumerable.Cast

If an element cannot be cast to type TResult, this method will throw an exception.如果一个元素无法转换为 TResult 类型,则此方法将引发异常。 To obtain only those elements that can be cast to type TResult, use the OfType method instead of Cast(IEnumerable).要仅获取那些可以强制转换为 TResult 类型的元素,请使用 OfType 方法而不是 Cast(IEnumerable)。


Edit based on these comments根据这些评论进行编辑

Established that all items returned are of type Item and not SubItem .确定返回的所有项目都是Item而不是SubItem类型。 This explains the exception.这解释了异常。

... said that the List consists of Item that´s why I want to downcast them to SubItem. ...说列表由项目组成,这就是为什么我想将它们向下转换为子项目。

Your inheritance hierarchy as you have posted it in your question is System.Object -> Item -> SubItem .您在问题中发布的继承层次结构是System.Object -> Item -> SubItem ( I include Object as I am assuming we are dealing with reference types and also everything eventually inherits from System.Object ). 我包括 Object ,因为我假设我们正在处理引用类型,并且所有东西最终都继承自 System.Object )。 What this means is that a SubItem could be cast to an Item or an System.Object , an Item instance could be cast to a System.Object .这意味着SubItem可以转换为ItemSystem.ObjectItem实例可以转换为System.Object However the inverse is not true, you cant cast up the graph.然而,逆是不正确的,你不能投出图表。 An instance of System.Object cannot become an Item and an Item cannot become a SubItem . System.Object的实例不能成为Item并且Item不能成为SubItem

Having a generic List<Item> is fine, this could contain types SubItem or Item or anything that derives from Item .拥有一个通用的List<Item>很好,它可以包含类型SubItemItem或任何派生自Item东西。 But again, you cannot cast an instance of Item to SubItem .但同样,您不能将Item的实例转换为SubItem

If this is not clear then I recommend you do some reading up on inheritance as well as Polymorphism which is a different topic but also very important if you want to know why inheritance is used and what makes it such a great tool for abstraction.如果这还不清楚,那么我建议您阅读有关继承和多态的一些内容,这是一个不同的主题,但如果您想知道为什么使用继承以及是什么使它成为如此出色的抽象工具,这也非常重要。

It could be that some of the items in your list are not of the derived class type, you should be able to see this in the debugger.可能是您列表中的某些项目不是派生类类型,您应该能够在调试器中看到这一点。 Also as someone has pointed out you may have to pull the data back from the database before doing the cast, the linq provider may not be capable of doing that for you.另外,正如有人指出的那样,您可能必须在进行转换之前从数据库中取回数据,因此 linq 提供程序可能无法为您执行此操作。

So you could try either of the following:因此,您可以尝试以下任一方法:

  • Filter out items that are not of SubItem过滤掉不属于 SubItem 的项目
var items = Inventory.FindAll(x=> x.id==id).OfType<SubItem>().ToList();
  • Pull the data back from the database before casting转换前从数据库中取回数据
var items = Inventory.FindAll(x=> x.id==id).ToList().Cast<SubItem>().ToList();
  • Or a combination of the two if the linq provider cannot do the OfType或者,如果 linq 提供程序不能执行 OfType,则将两者结合使用
var items = Inventory.FindAll(x=> x.id==id).ToList().OfType<SubItem>().ToList();

Assuming that Inventory contains a list of "Item" and you want to get a list of "SubItem" replace your line with this:假设 Inventory 包含一个“Item”列表,并且您想获得一个“SubItem”列表,将您的行替换为:

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

So the first part is going to get you the items that meet your conditions and the second part will create a new SubItem for each one and give you a list of them.因此,第一部分将为您提供符合您条件的项目,第二部分将为每个项目创建一个新的子项目并为您提供它们的列表。

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

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