Polymorphism allows classes to transform into a different class within its inheritance hierarchy. It allows a programmer to use objects of different types but treat them in their “general” form while maintaining their specific functionality. For example, there are many kinds of animals such as dogs, cats, and birds, but you can treat them generally as animals. All animals eat food, but they eat in different ways. All animals can move, but they move in different ways. We don’t care about how they do them specifically. It is up to each object to use its own implementation of those functions. This is the essence of polymorphism. In a program, for example, you can create several instances of the Animal class. You can assign instances of other classes to it as long as its type is a subtype of Animal thanks to inheritance. Let’s look at an example behavior of polymorphism.

using System;
 
namespace PolymorphismDemo
{
    class Animal
    {
        public virtual void Eat()
        {
            Console.WriteLine("The animal ate!");
        }
    }
 
    class Dog : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("The dog ate!");
        }
    }
 
    class Bird : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("The bird ate!");
        }
    }
 
    class Fish : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("The fish ate!");
        }
    }
 
    class Program
    {
        public static void Main()
        {
            Dog myDog = new Dog();
            Bird myBird = new Bird();
            Fish myFish = new Fish();
            Animal myAnimal = new Animal();
 
            myAnimal.Eat();      
                                 
            myAnimal = myDog;    
            myAnimal.Eat();      
            myAnimal = myBird;   
            myAnimal.Eat();      
            myAnimal = myFish;   
            myAnimal.Eat();      
        }
    }
}

Example 1 – Polymorphism Demo

The animal ate!
The dog ate!
The bird ate!
The fish ate!

We defined 4 different classes. The Animal is the base class and will be derived by the other three classes. Each of the class has their own version of the Eat() method. We created instances for each class. We then called the Eat() method of the Animal instance as shown below.

Animal myAnimal = new Animal();
 
myAnimal.Eat();

The polymorphism takes place next. We assigned the Dog object to the Animal instance and called the Eat() method again. Now even though we are using an Animal instance, the Eat() method of the Dog class was called. This is the effect of polymorphism. We then assigned the other two objects (Bird and Fish) to the Animal instance and called their respective Eat methods. Notice that when we assigned the objects to the Animal instance, we didn’t use casting. This is because no casting is required if you are storing an object of a derived class to an object that has a type which is higher than that of the derived class in the inheritance hierarchy.

You can also initialize an Animal class with the constructor of any of its derived classes.

Animal myDog = new Dog();
Animal myBird = new Bird();
Animal myFish = new Fish();

myDog.Eat();
myBird.Eat();
myFish.Eat();

The code above will yield the same output as Example 1. Let’s modify our program to show another concept of polymorphism.

using System;
 
namespace PolymorphismDemo2
{
    class Animal
    {
        public virtual void Eat()
        {
            Console.WriteLine("The animal ate!");
        }
    }
 
    class Dog : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("The dog ate!");
        }
 
        public override void Run()
        {
            Console.WriteLine("The dog ran!");
        }
    }
 
    class Bird : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("The bird ate!");
        }
 
        public override void Fly()
        {
            Console.WriteLine("The bird flew!");
        }
    }
 
    class Fish : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("The fish ate!");
        }
 
        public override void Swim()
        {
            Console.WriteLine("The fish swam!");
        }
    }
 
    class Program
    {
        public static void Main()
        {
            Animal animal1 = new Dog();
            Animal animal2 = new Bird();
            Animal animal3 = new Fish();
 
            Dog myDog = (Dog)animal1;
            Bird myBird = (Bird)animal2;
            Fish myFish = (Fish)animal3;
 
            myDog.Run();
            myBird.Fly();
            myFish.Swim();
        }
    }
}

Example 2 – Polymorphism Demo 2

The dog ran!
The bird flew!
The fish swam!

We created three Animal objects and initialized them using the three derived class constructors. We used casting to store those animal objects to their respective instances. We do this so we can call the unique methods for each of the derived classes. There is a shorthand way of doing this, but you will not be able to store the object. It is demonstrated by the following code:

((Dog)animal1).Run();
((Bird)animal2).Fly();
((Fish)animal3).Swim();

We simply put the expression inside parentheses since the expression will result into an anonymous object.

using System;
 
namespace PolymorphismDemo3
{
    interface IAnimal
    {
        void Eat();
    }
 
    class Dog : IAnimal
    {
        public void Eat()
        {
            Console.WriteLine("The dog ate!");
        }
    }
 
    class Bird : IAnimal
    {
        public void Eat()
        {
            Console.WriteLine("The bird ate!");
        }
    }
 
    class Fish : IAnimal
    {
        public void Eat()
        {
            Console.WriteLine("The fish ate!");
        }
    }
 
    class Program
    {
        public static void Main()
        {
            IAnimal myDog = new Dog();
            IAnimal myBird = new Bird();
            IAnimal myFish = new Fish();
 
            myDog.Eat();
            myBird.Eat();
            myFish.Eat();
        }
    }
}

You can also use polymorphism on interfaces. The code below shows you just that.

Example 3 – Polymorphism With Interfaces

The dog ate!
The bird ate!
The fish ate!

Mastering polymorphism and inheritance are required to be able to fully understand the world of .NET programming.