Introduction
This article explains how to apply polymorphic behavior backward in the class hierarchy.
Using the Code
This article uses Visual Studio 2008.
The Problem
You may want to apply polymorphic behaviour to the classes of different levels of the inheritance hierarchy that do not have a common interface. For example, imagine that you have an array of objects of different types inherited from the same base class. You'd like to call a method for all the objects in the array, but the method only exists in one of the inherited classes.
The most reasonable thing would be to move the method up in the hierarchy (and make it virtual, if needed). However, it is not always in your hands - the base class can be in a third-party library, or inaccessible due to other reasons.
The Solution
Using an extension method will allow you to do the trick. Here is the example.
Create a base class called Animal
. Assume it is the class that is out of your reach, and you cannot modify it.
public abstract class Animal
{
}
Create an inherited class DomesticAnimal
that introduces the method Says()
. This is the method you'd like to call across all the classes inherited from Animal
.
public class DomesticAnimal : Animal
{
public virtual string Says()
{
return null;
}
}
Create classes Cat
and Dog
that inherit from DomesticAnimal
and implement the method Says()
.
public class Cat : DomesticAnimal
{
public override string Says()
{
return "Meow!";
}
}
public class Dog : DomesticAnimal
{
public override string Says()
{
return "Woof!";
}
}
Create a class Wolf
that inherits directly from Animal
and thus does not have the Says()
method.
public class Wolf: Animal
{
}
Now imagine a client code that creates an array of the above Animal
objects and wants to call Says()
method on each object in the array, including Wolf
.
static void Main(string[] args)
{
Animal[] animals = new Animal[3];
animals[0] = new Cat();
animals[1] = new Dog();
animals[2] = new Wolf();
foreach (Animal animal in animals)
{
Console.WriteLine("{0} says {1}",
animal.GetType().Name, animal.Says());
}
}
Of course this code would not compile. The following error will show up, pointing to the Animal.Says()
method:
'BackwardPolymorphism.Animal' does not contain a definition for 'Says'
and no extension method 'Says' accepting a first argument of type
'BackwardPolymorphism.Animal' could be found
(are you missing a using directive or an assembly reference?)
Let's now add a new static
class that will provide an extension method Says()
for Animal
class (note the same name of the extension and inherited methods). We have to check object type dynamically and cast the object in order to call the intrinsic Says()
method of the inherited classes.
public static class AnimalExtension
{
public static string Says(this Animal animal)
{
string says = "[Unknown]";
if (animal is DomesticAnimal)
{
says = ((DomesticAnimal)animal).Says();
}
return says;
}
}
Now the code will compile. When running, it produces the following output:
History
- 19th June, 2009: Initial version