Inheritance and polymorphism in C#

1- Introduction

Inheritance and polymorphism - this is a very important concept in C#. You must understand it better if you want to learn C#.

2- Class, object and constructor

You need to understand explicitly about class, constructor and instance before starting to learn inheritance in C#. We see class Person, describes a person with the relevant information.
 
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class Person
    {
        // Name of person
        public String Name;

        // Year of Birth
        public int BornYear;

        // Place of Birth
        public String PlaceOfBirth;

        // The Constructor has 3 parameters. The aim to initialize the value for fields of Person.
        // Specify the name, year of birth, place of birth.
        public Person(String Name, int BornYear, String PlaceOfBirth)
        {
            this.Name = Name;
            this.BornYear = BornYear;
            this.PlaceOfBirth = PlaceOfBirth;
        }

        // The Constructor have 2 parameters.
        // Purpose initialize for two fields (name & Born year) of Person.
        // PlaceOfBirth not be initialized.
        public Person(String Name, int BornYear)
        {
            this.Name = Name;
            this.BornYear = BornYear;
        }

    }
}
PersonDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class PersonDemo
    {

        static void Main(string[] args)
        {

            // Instance: Thomas Edison.
            // Initiated by constructor with 2 parameters.
            Person edison = new Person("Thomas Edison", 1847);

            Console.WriteLine("Info:");
            Console.WriteLine("Name: " + edison.Name);
            Console.WriteLine("Born Year: " + edison.BornYear);
            Console.WriteLine("Place Of Birth: " + edison.PlaceOfBirth);

            // Instance: Bill Gates.
            // Initiated by constructor with 3 parameters.
            Person billGates = new Person("Bill Gate", 1955, "Seattle, Washington");

            Console.WriteLine("-----------------------------------");

            Console.WriteLine("Info:");
            Console.WriteLine("Name: " + billGates.Name);
            Console.WriteLine("Born Year: " + billGates.BornYear);
            Console.WriteLine("Place Of Birth: " + billGates.PlaceOfBirth);

            Console.ReadLine();
        }
    }
}
Running PersonDemo:

Distinguishing Class,constructor and instance:

Person simulate a class of people, it is something abstract, but it has information, in the example above, information is the name, year of birth, place of birth.

Constructor
  • Constructor always have the same name as the class
  • One class has one or more constructors.
  • Constructor with or without parameters, no parameters constructor called default constructor.
  • Constructor using for create a instance of class.

3- Inheritance in CSharp

We need a few classes to participate in examples.
  • Animal: Class simulate an animal.
  • Duck: Subclass of Animal.
  • Cat: Subclass of Animal.
  • Mouse: Subclass of Animal.
Example:
Animal.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public abstract class Animal
    {
        // Name field.
        // for example, Tom cat, Jerry mouse.
        public string Name;

        // Default constructor.
        public Animal()
        {
            Console.WriteLine("- Animal()");
        }

        public Animal(string Name)
        {
            // Assign a value to the Name field.
            this.Name = Name;
            Console.WriteLine("- Animal(string)");
        }

        // The method describes animal movement.
        // Virtual: Saying that this method may be overridden in subclasses.
        public virtual void Move()
        {
            Console.WriteLine("Animal Move");
        }

        public void Sleep()
        {
            Console.WriteLine("Sleep");
        }

    }
}
Cat is the class that inherits from the Animal class, it also has its fields.
Cat.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public class Cat : Animal
    {

        public int Age;
        public int Height;

        // This is Constructor with 3 parameters
        // Using :base(name) to call constructor of parent: Animal(string).
        // The fields of superclass will be assigned values.
        // Then the fields of this class is assigned values.
        public Cat(string name, int Age, int Height)
            : base(name)
        {
            this.Age = Age;
            this.Height = Height;
            Console.WriteLine("- Cat(string,int,int)");
        }

        // This constructor call to default constructor of superclass.
        public Cat(int Age, int Height)
            : base()
        {
            this.Age = Age;
            this.Height = Height;
            Console.WriteLine("- Cat(int,int)");
        }

        public void Say()
        {
            Console.WriteLine("Meo");
        }

        // Override method in parent class.
        // (describe how a cat moves)
        public override void Move()
        {
            Console.WriteLine("Cat Move ...");
        }
    }
}
CatTest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class CatTest
    {
        static void Main(string[] args)
        {

            Console.WriteLine("Create Cat object from Cat(string,int,int)");

            // Create a Cat object from constructor with 3 parameters
            // Name of Animal assigned the value "Tom".
            // Age of Cat assigned the value 3
            // Height of Cat assigned the value 20.
            Cat tom = new Cat("Tom",3, 20);

            Console.WriteLine("------");
            
            Console.WriteLine("Name = {0}", tom.Name);
            Console.WriteLine("Age = {0}", tom.Age);
            Console.WriteLine("Height = {0}", tom.Height);

            Console.WriteLine("------");

            // Call method inherited from Animal
            tom.Sleep();

            // Call Say() method (of Cat)
            tom.Say();


            Console.ReadLine();
        }
    }
}
Kết quả chạy class CatTest:
What's happened when you create an object from constructor . How does it call up a constructor of the parent class? Please see the illustration below:
With the above illustration you see that, constructor of  parent class is always called before constructor of  subclass, it will assign values to the fields of the parent class, then the fields of the subclass.
When you write a constructor which is not explicitly declared that it is based from which constructor of parent class, CSharp is understood that such constructor is based from default constructor of parent class.
// this constructor not specified 'base'
public Cat(int Age, int Height)
{

}

// It would be equivalent to:
public Cat(int Age, int Height) : base()
{
 
}
A constructor may call other constituents by using: this.
private int Weight;

// Default constructor (Without parameters).
// Call to Mouse(int)
public Mouse()    : this(100)
{
}

// Constructor with one parameter.
// Not specified :base
// (Its based from default constructor of parent class)
public Mouse(int Weight)
{            
   this.Weight = Weight;
}
Mouse.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public class Mouse : Animal
    {

        private int Weight;

        // Default constructor (Without parameter)
        // Call to Mouse(int)
        public Mouse()
            : this(100)
        {
        }

        // Constructor with one parameter
        // Not specified 'base'.
        // This constructor based from default constructor of parent class.
        public Mouse(int Weight)
        {            
            this.Weight = Weight;
        }

        // Constructor with 2 parameter.
        public Mouse(String name, int Weight)
            : base(name)
        {
            this.Weight = Weight;
        }

        public int GetWeight()
        {
            return Weight;
        }

        public void SetWeight(int Weight)
        {
            this.Weight = Weight;
        }

 
    }
}
You can use "is" operator to check an object is the type of a certain Type or not. See the example below:
IsOperatorDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class IsOperatorDemo
    {
        static void Main(string[] args)
        {
            // Create Animal object.
            // Animal is abstract class
            // so can not create objects from the constructor of Animal.
            Animal tom = new Cat("Tom", 3, 20);

            Console.WriteLine("Animal Sleep:");

            // Call Sleep() method of Animal
            tom.Sleep();

            // Using the operator 'is' to check the type of an object
            bool isMouse = tom is Mouse;// false

            Console.WriteLine("Tom is mouse? " + isMouse);

            bool isCat = tom is Cat; // true
            Console.WriteLine("Tom is cat? " + isCat);

            bool isAnimal = tom is Animal; // true
            Console.WriteLine("Tom is animal? " + isAnimal);

            Console.ReadLine();
        }
    }
}
Running the example:

Cast in C Sharp.

CastDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class CastDemo
    {
        static void Main(string[] args)
        {
            // Call method returns a random Animal.
            Animal animal = GetRandomAnimal();

            if (animal is Cat)
            {
                Console.WriteLine("Your animal is Cat");

                // Cast to Cat
                Cat cat = (Cat)animal;

                // And access Height of Cat
                Console.WriteLine("Cat height: " + cat.Height);
            }
            else if (animal is Mouse)
            {
                Console.WriteLine("Your animal is Mouse");

                // Cast to Mouse
                Mouse mouse = (Mouse)animal;

                // Call method of Mouse
                Console.WriteLine("Mouse weight: " + mouse.GetWeight());
            }

            Console.ReadLine();
        }

        // The method returns random Animal.
        public static Animal GetRandomAnimal()
        {
            // return random number between 0 and 9 (0,..9)
            int random = new Random().Next(0, 10);

            Console.WriteLine("random = " + random);

            Animal animal = null;
            if (random < 5)
            {
                Console.WriteLine("Create a Cat");
                animal = new Cat("Tom", 3, 20);
            }
            else
            {
                Console.WriteLine("Create a Mouse");
                animal = new Mouse("Jerry", 5);
            }
            return animal;
        }
    }
}
Running the example:

4- Polymorphism in CSharp

The word polymorphism means having many forms. In object-oriented programming paradigm, polymorphism is often expressed as 'one interface, multiple functions'.

Polymorphism can be static or dynamic. In static polymorphism, the response to a function is determined at the compile time. In dynamic polymorphism, it is decided at run-time.
You have a cat Asian Cat, you can call it is a Cat or call it is an Animal which is an aspect of the polymorphism.

Or another example: On your resume records that you're an Asian man, while you actually are a Vietnamese.

The example below shows you how to behave between declaring and reality
PolymorphismCatDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class PolymorphismCatDemo
    {
        static void Main(string[] args)
        {
            // Declare an Animal object
            // By creating it by constructor of the Cat class.
            // Instance 'tom' declared as Animal

            Animal tom = new Cat("Tom", 3, 20);


            // Call Sleep() method
            tom.Sleep();

            // Call Move() method.
            // Move() defined in Animal class
            // Move() is overridden in class Cat
            // ==> Call Move() defined in Cat.
            tom.Move(); // ==> Cat Move.


            Console.ReadLine();
        }
    }
}
You have two ways to override a method from the superclass override and new. See the illustration below:
Duck.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
   class Duck : Animal
   {

       public Duck(string name)
           : base(name)
       {
           Console.WriteLine("- Duck(string)");
       }


       public new void Move()
       {
           Console.WriteLine("Duck Move..");
       }
   }
}
InheritanceDuckDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class InheritanceDuckDemo
    {
        static void Main(string[] args)
        {
            // Declare an Animal object
            // By creating it by constructor of the Duck class.
            // Instance 'donald' declared as Animal

            Animal donald = new Duck("Donald");


            // Call Sleep method (defined in Animal).
            donald.Sleep();

            // Call Move() method.
            // Move() defined in Animal class
            // Move() is 'new' in class Duck (Using only for Duck or subclasses).
            // (Instance 'donald' declared as Animal, not Duck)
            // ==> Call Move() defined in Animal.
            donald.Move(); // ==> Animal Move.


            Console.ReadLine();
        }
    }
}
Running the example: