Given the following class structure:
class Base {}
class DerivedA: Base {}
class DerivedB: Base {}
class Container
{
public List<Base> Items { get; }
}
where the list of Derived objects grows over time as my application develops more functionality. I’m trying to do:
Container container = ReturnsContainer();
foreach (var item in container.Items)
{
doStuff(item);
}
where doStuff(item) is overloaded by derived type.
void doStuff(DerivedA) {}
void doStuff(DerivedB) {}
That doesn’t work as the compiler says “cannot convert from ‘Base’ to ‘DerivedA'” and “The best overloaded method match doStuff(DerivedA) has some invalid arguments”. The best approach I can come up with is:
Container container = ReturnsContainer();
foreach (var item in container.Items)
{
if (item is DerivedA)
{
doStuff((DerivedA)item);
}
else if (item is DerivedB)
{
doStuff((DerivedB)item);
}
}
Any thoughts on how I can make this cleaner? Since my Derived types will only grow over time, I would have to go back and add to this long if structure to continue to make this work.
I think the container.Items.OfType<> solution would translate to a growing (and unnecessary) performance hit as the number of Derived types increases.
Do I have to use generic delegates for this? Seems like an overly complex solution for something that feels like it should be simple polymorphism.
Edit: For further clarity, let’s say the Base and Derived type hierarchy is on a separate API layer and is not modifiable (final classes). The solution has to work with the existing inheritance structure and cannot extend the Base and Derived objects. Though the API layer can grow new Derived classes as time goes on.
There are a couple of options here, but it really boils down to how can
doStuufknow what to do if you’re going to add new derived types in the future?So, one option is if
Containerreally does only contain 1 type at a time then you could make it generic:Now when you iterate it, you know that
Itemsis a List ofDerivedAorDerivedBThis would mean you either have multiple
doStuffmethodsor if more appropriate you can have 1 which takes the base
That is the advantage of simple polymorhism!
The second option is to define
doStuffas taking adynamicif you’re using C#3.5But I would personally avoid this option!