C# Inheritance – Adding Base-Class Functionality to Uncontrolled Classes

cgenericsinheritancemodelingmultiple-inheritance

I have a set of classes from a 3rd party library. These classes use an inheritance structure to share logic. I would like to add a layer of abstraction in the middle of their inheritance tree to add functionality to all of the children (concrete) implementations.

Here is a simplified example of the classes in the 3rd party lib:

public interface IAnimal
{
    bool IsMammal { get; }
}

public abstract class Animal : IAnimal
{
    public abstract bool IsMammal { get; }
    public string Name { get; set; }
}

public class Cat : Animal
{
    public override bool IsMammal { get { return true; } }
    public void Pur() {}
}

public class Dog : Animal
{
    public override bool IsMammal { get { return true; } }
    public void Fetch() {}
}

public class Snake : Animal
{
    public override bool IsMammal { get { return false; } }
    public void ShedSkin() {}
}

I would like to add the concept of an AnimalWithSuperPower. These types of animals should have 1 additional Property; SuperPower. I would like to be able to have classes like CatWithSuperPower which derive from Cat, AnimalWithSuperPower, & Animal so that I can access all the functionality of those.

Here is the definition of SuperPower:

public enum SuperPower { Invisibility, SuperStrength, XRayVision }

My first idea was to use multiple inheritance. But unfortunately, C# doesn't support multiple base classes.

private abstract class AnimalWithSuperPower : Animal
{
    public SuperPower SuperPower { get; set; }
}

// doesn't compile because you can't extend 2 classes
private class DogWithSuperPower : AnimalWithSuperPower, Dog {}

My next attempt uses a combination of inheritance, composition, and generics to try to deliver the functionality of the base classes.

private abstract class AnimalWithSuperPower<TAnimalType> : Animal where TAnimalType : IAnimal
{
    public SuperPower SuperPower { get; set; }

    protected readonly TAnimalType Animal;

    protected AnimalWithSuperPower()
    {
        Animal = (TAnimalType) Activator.CreateInstance(typeof(TAnimalType));
    }
}

private class SuperCat : AnimalWithSuperPower<Cat>
{
    public override bool IsMammal { get { return Animal.IsMammal; } }
}

private class SuperCatWithPur : AnimalWithSuperPower<Cat>
{
    public override bool IsMammal { get { return Animal.IsMammal; } }

    public void Pur() // needing duplicate pass-through methods/properties like this is painful :(
    {
        Animal.Pur();
    }
}

private static void ExampleUsage()
{
    var invisibleCat = new SuperCat { SuperPower = SuperPower.Invisibility };
    invisibleCat.Pur(); // doesn't compile - can't access Pur() method because doesn't extend Cat

    var xrayCat = new SuperCatWithPur { SuperPower = SuperPower.XRayVision };
    xrayCat.Pur(); // only works because I exposed the method with the EXACT same signature
}

This solution is not very good (IMO) because of these reasons:

  • SuperCat and SuperCatWithPur aren't actually instances of Cat
  • any method you wish to use from Cat needs to be mirrored in the container class
  • feels kind of messy: AnimalWithSuperPower is an Animal but it also takes an Animal type parameter

I also tried doing it with an extension method but it wasn't any better than the above two attempts:

private abstract class AnimalWithSuperPower : Animal
{
    public SuperPower SuperPower { get; set; }
}

private static AnimalWithSuperPower WithSuperPower(this Animal animal, SuperPower superPower)
{
    var superAnimal = (AnimalWithSuperPower) animal;
    superAnimal.SuperPower = superPower;
    return superAnimal;
}

private static void ExampleUsage()
{
    var dog = new Dog { Name = "Max" };
    var superDog = dog.WithSuperPower(SuperPower.SuperStrength);
    superDog.Fetch(); // doesn't compile - superDog isn't an instance of Dog
}

If I had control of the 3rd party classes, I could likely do this cleanly by introducing a new class in the middle of the inheritance tree, but I can't

My Question:

How can I model AnimalWithSuperPower so that:

  • instances are considered of types Cat (or appropriate sub-class), Animal, & AnimalWithSuperPower
  • all the methods and properties are available without extra pass-through calls

Best Answer

Why don't you just use interfaces?

If you're concerned about sharing functionality, you can use extension methods to serve as your pseudo-base class. It's not exactly ideal, but it should get what you're looking for done.

Something along the lines of:

public interface IAnimalWithSuperPower {
    public SuperPower power { get; set; }
}

public class SuperCat : Cat, IAnimalWithSuperPower {
    public SuperPower power { get; set; }
    public SuperCat() {
        SuperPower = SuperPower.SuperStrength;
    }
}

public static void UseSuperPower(this IAnimalWithSuperPower animal) {
    animal.power.doSomething();
}