Polymorphism

.Polymorphism


Polymorphism Program Output

.Polymorphism

"A C# program which illustrates polymorphism along with upcasting, downcasting, the "is" and "as" operators, and the InvalidCastException exception."

The program creates a base class with three derived classes. All the derived classes are stored in a base class array and the array is traversed to show how polymorphism is used to invoke the methods from the derived classes. An example of upcasting in show. Both successful and unsuccessful examples of downcasting are shown. It is shown how to use the "is" operator to check for type compatibility and the "as" operator to perform a cast operation with the reference variable being set to null on cast failure (instead of throwing an exception). A traditional explicit downcast is shown with an example of an InvalidCastException. The following C# features are used in the sample code:

  1. Polymorphism - At run time, objects of a derived class may be treated as objects of a base class in places such as method parameters and collections or arrays.
  2. Inheritance - Create new classes that reuse, extend, and modify the behavior that is defined in other classes.
  3. As Operator - "as" operator is like a cast operation except on cast failure it returns null instead of raising an exception.
  4. Is Operator - "is" operator returns true if reference variable is non-null and the object can be cast to the provided type.
  5. InvalidCastException Class - Exception that is thrown for invalid casting or explicit conversion.

Polymorphism

/*
* C# Polymorphism
*
* Polymorphism is the behavior of an object to respond to a
* call to its methods based on the object type at run time.
* Polymorphism is enabled by redefining methods in derived classes.
*
* In this example, derived class methods are invoked through
* a base class reference.
*/

namespace Polymorphism
{
    class Animal
    {
        public virtual void MakeNoise() { System.Console.WriteLine("Base class: an animal noise"); }
    }

    class Dog : Animal
    {
        public override void MakeNoise() { System.Console.WriteLine("Dog: Bark"); }
    }
    class Cat : Animal
    {
        public override void MakeNoise() { System.Console.WriteLine("Cat: Meow"); }
    }

    class Chihuahua : Dog
    {
        public override void MakeNoise() { System.Console.WriteLine("Chihuaua: Arf"); }
    }

    class Program
    {
        static void Header()
        {
            System.Console.WriteLine("************************************************************************");
            System.Console.WriteLine("*** Polymorphism, upcast, downcast, \"is\", \"as\", InvalidCastException ***");
            System.Console.WriteLine("************************************************************************\n");
        }

        static void Main()
        {
            Program.Header();

            System.Console.WriteLine("*** Upcast to store in array, but still call derived method ***");
            // Upcast derived classes and store in base class array
            Animal[] myAnimals = new Animal[3];
            myAnimals[0] = new Dog();
            myAnimals[1] = new Cat();
            myAnimals[2] = new Chihuahua();

            // Method invoked is based on the run-time type of each object
            foreach (Animal animal in myAnimals)
                animal.MakeNoise();    // Prints: Bark, Meow, Arf
            System.Console.WriteLine();

            // Upcast always succeeds (cast the derived class to base class)
            Animal myAnimal = new Animal();
            Dog myDog = new Dog();
            myAnimal = myDog; // Implicit upcast
           
            // Unsucessful Downcast (cast the base class to the derived class)
            Animal myAnimal2 = new Animal();
            Dog myDog2 = new Dog();
            //myDog2 = (Dog) myAnimal2; // InvalidCastException (myAnimal2 was not born a Dog)

            // Successful Downcast (must be upcast first, before can be downcast)
            // i.e. must be "born" a Dog before can be downcast as a Dog
            Dog myDog3 = new Dog();
            Animal myAnimal3 = new Animal();

            myAnimal3 = myDog3; // Implicit Upcast
            myDog3 = (Dog)myAnimal3; // Successful Downcast (born a Dog)

            System.Console.WriteLine("*** \"is\" operator test for type compatibility ***");
            // Use "is" a.k.a. "is compatible with" operator to test for compatible types
            // i.e. tests if object can be cast without causing an exception
            if (myDog2 is Animal)
            {
                System.Console.WriteLine("myDog2 is an Animal"); // Prints
            }
            if (myDog2 is Dog)
                System.Console.WriteLine("myDog2 is a Dog"); // Prints

            if (myAnimal2 is Dog)
                System.Console.WriteLine("myAnimal2 is a Dog");
            else
                System.Console.WriteLine("myAnimal2 is NOT a Dog"); // This one prints
            System.Console.WriteLine();

            // As operator performs cast or returns null (does not throw an exception)
            // As operator only works with reference types
            // As has best performances better because Null comparison is faster than
            //    catching exception (traditional cast) or performing the cast twice ("is")
            System.Console.WriteLine("*** \"as\" returns null if cast fails (best cast performance) ***");
            myDog2 = myAnimal2 as Dog;

            if (myDog2 == null) // "As" sets variable to null if cast fails
                System.Console.WriteLine("Cast of myDog2 was NOT successful");

            Animal myAnimal4 = new Dog();
            myAnimal2 = myAnimal4;
            myAnimal4 = myAnimal2 as Dog;
            if (myAnimal4 == null)
                System.Console.WriteLine("Cast of myAnimal4 was NOT successful");
            else
                System.Console.WriteLine("Cast of myAnimal4 was successful"); // This one Prints
            System.Console.WriteLine();
        }
    }
}