How can I downcast a list of objects so that each of the objects in the list is downcast to an object of a derived class?
This is the scenario.
I have a base class with a List
of base items, and two classes inheriting from it:
public class BaseClass
{
public List<BaseItem> items;
protected BaseClass()
{
// some code to build list of items
}
}
public class DerivedClass : BaseClass
{
public DerivedClass : base() {}
}
public class AnotherDerivedClass : BaseClass
{
public AnotherDerivedClass : base() {}
}
public class BaseItem {}
public class DerivedItem : BaseItem {}
public class AnotherDerivedItem : BaseItem {}
The idea is to not have to duplicate the code needed to build the list of items. The BaseItem
has all the basic stuff I need, and I can always downcast BaseItem
to one of the derived items.
The problem arises when I have a list of them. The List
of BaseItem
is declared in the BaseClass
because all the derived classes have to have it. But when accessing it at runtime I can't seem to be able to downcast to the derived class.
I believe what you want to do is use generics:
This will cause the
items
inDerivedClass
to beList<DerivedItem>
. Thewhere
enforces that only types that derive fromBaseItem
can be used.edit: "downcasting", casting a type to a derived type, isn't really what you are trying to do here. Your intent is that the derived list objects use a specific derived item type by design, and presumably you want to store instantiated objects of the derived type in your derived list class.
So, this could work just fine without using generics: the
List<BaseItem>
is perfectly capable of storing any items that derive fromBaseItem
. However, you would have to reference these objects from the list using casting (as described in the other answers) in order to access the derived properties. But that is simply "casting" an object to it's true type. Generics gives you a way to provide strongly typed access to these objects directly.Basically, storing an object in a container that is a superclass of the object doesn't change anything about the object - it only changes the way your code can refer to it, by making it appear to be the simpler type from which it derives.
Using LINQ:
Note: Having to downcast usually is a 'smell' and indicates that the inheritance hierarchy is wrong, or wrongly implemented. The idea of having a base class is that you can treat all subclasses as superclass without having to downcast to individual subclass types.
Instead of
Cast
you might want to useOfType
to 'fish out' certain derived classes from a collection of superclasses. But again, there should be no need to do that.Ask yourself, why you need to have a subclass - maybe you need to move some functionality to base class?
...
PettingZoo is not interchangeable with Zoo, as a PettingZoo should restrict the types of Animals. As such, this design fails the Liskov substitution principle.
You can also use LINQ to iterate through the elements of the base class and downcast each element, like this:
If you need to check the derived type of each element before casting:
For more information, take a look at the following articles: