Mixing generics and polymorphism

Polymorphism, which attempts to hide differences in implementation, and generics, which attemtps to highlight them by providing exact information about types, don’t seem to mix very well. Consider the following fairly common pattern.

        class Base
{
}

class Derived : Base
{
}

abstract class Manipulator
{
List<Base> list;

public Manipulator(List<Base> list)
{
this.list = list;
}
}

class BaseManipulator : Manipulator
{
public BaseManipulator(List<Base> list)
: base(list)
{ }
}

class DerivedManipulator : Manipulator
{
public DerivedManipulator(List<Derived> list)
: base(list)
{ }
}

public static void Main()
{
List<Derived> list = new List<Derived>();
list.Add(new Derived());
DerivedManipulator d = new DerivedManipulator(list);
}


The code above will not compile – the compiler complains that List<Derived> cannot be converted to List<Base> in DerivedManipulator’s constructor. Which seems kindof strange, given that Derived[] is implicitly convertible to Base[]. But what would happen if implicit conversion occurred with generics?

List<Derived> derivedList = new List<Derived>();
List<Base> baseList = derivedList;
baseList.Add(new Base());
Derived d = derivedList[0]; // BOOM

All hell will break loose. The type safety that generics offer will disappear, obviating the very need for generics.


What can be done then? We could make Manipulator a generic class, taking the type of the List as a generic parameter and make DerivedManipulator derive from Manipulator<Derived>. But then we are only shifting the problem – treating Manipulators polymorphically becomes impossible then.


There seems to be a basic impedance mismatch between polymorphism and generics. Does anyone know of a better way to solve the problem?

6 thoughts on “Mixing generics and polymorphism”

  1. class DerivedManipulator : Manipulator
    {
    public DerivedManipulator(List list)
    : base(list)
    { }
    }

    public static void Main()
    {
    List list = new List();
    list.Add(new Derived());
    DerivedManipulator d = new DerivedManipulator(list);
    }

  2. pjsson : You lose typesafety with your approach. The whole point of using List was to make sure that DerivedManipulator can take only a list of Derived instances.

  3. You can use generic parameter for Manipulator which must inherit from Base. By specifying virtual method Merge in manipulator, you can organize merging two items hierarchycally. Here is complete code:

    abstract class Item { }

    class Base { }

    class Derived : Base { }

    abstract class Manipulator
    where TItem : Item
    {
    List
    list;

    public Manipulator(List list)
    {
    this.list = list;
    }

    public virtual TItem Merge(TItem x, TItem y)
    { }
    }

    class BaseManipulator : Manipulator
    {
    public BaseManipulator(List list)
    : base(list)
    { }
    }

    class DerivedManipulator : Manipulator
    {
    public DerivedManipulator(List
    list)
    : base(list)
    { }
    }

  4. Bojan,

    Like I mentioned in the blog post, that only shifts the problem – with your code, it becomes impossible to treat Manipulators polymorphically. I can’t do

    Manipulator<Base> = new Manipulator<Derived>

    for example.

Leave a Reply

Your email address will not be published. Required fields are marked *


*