简体   繁体   中英

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>

Now, when I execute the Code I always get an InvalidCastException in System.Core.dll ""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. Item inherits from IEquatable.

The LINQ is definitely working, but when I am casting I get the Error. 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> ).

The InvalidCastException will occur when calling Cast if one or more items is not of the type specified in the generic argument. See details in the Microsoft page 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 . Your code then becomes:

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

From the documentation Enumerable.Cast

If an element cannot be cast to type TResult, this method will throw an exception. To obtain only those elements that can be cast to type TResult, use the OfType method instead of Cast(IEnumerable).


Edit based on these comments

Established that all items returned are of type Item and not 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 . ( I include Object as I am assuming we are dealing with reference types and also everything eventually inherits from 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 . 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 .

Having a generic List<Item> is fine, this could contain types SubItem or Item or anything that derives from Item . But again, you cannot cast an instance of Item to 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.

So you could try either of the following:

  • Filter out items that are not of 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
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:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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