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:
var items = Inventory.FindAll(x=> x.id==id).OfType<SubItem>().ToList();
var items = Inventory.FindAll(x=> x.id==id).ToList().Cast<SubItem>().ToList();
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.