4

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
1

1 Answer 1

6

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(); } 
4
  • In my trivial example code, the only functionality which I desire to share is the SuperPower property. Unfortunately, in my real-world problem, the AnimalWithSuperPower abstract class has several properties and methods which I want inherited by all the children. That being said... I am not sure which I prefer: needing multiple pass-through calls for all childrens' behaviour OR re-declaring the abstract behaviour repeatedly in all children. Which is the lesser of 2 evils? LOL Commented Jul 26, 2013 at 20:52
  • @JesseWebb: Neither. Prefer composition over inheritance. Put all your repeated code in a service and inject that into each animal that needs it. Commented Jul 26, 2013 at 22:09
  • 1
    @Cameron: Close, but I wouldn't call IAnimalWithSuperPower. There's nothing to say that every object implementing that interface must be an animal. Stick with IHasSuperPower. Commented Jul 26, 2013 at 22:12
  • @pdr: It may be worthwhile to define IHasSuperPower, but it's also necessary to define IAnimalWithSuperPower (and for animals that implement IHasSuperPower to also implement IAnimalWithSuperPower), because for a reference to be usable as both IAnimal and IHasSuperPower, it must be of a type that derives from both. Commented Mar 11, 2014 at 22:10

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.