To learn about Single & Double Dispatch, many design patterns, we need to understand Overloading and Overriding.

Overloading

Overloading is compile-time polymorphism. The methods/functions with same name but different number/type parameters are example of Overloading.

As Overloading is compile-time, means during run-time the base type is considered. Example:

        class Crop
        {
            public virtual void CropName()
            {
                Console.WriteLine("Hey, My type is Crop");
            }
        }

        class Wheat : Crop
        {
            public override void CropName()
            {
                Console.WriteLine("Hey, My type is Wheat");
            }
        }

        /* An example of overloading (Method with same name but different parameter type)
         * */
        class CropWatering
        {
            public void WaterSupply(Crop crop)
            {
                Console.WriteLine("I am working on type Crop");
            }

            public void WaterSupply(Wheat wheat)
            {
                Console.WriteLine("I am working on type Wheat");
            }
        }

In main, If I create an object of type Crop and Wheat, an expected result will appear in console.

        static void Main(string[] args)
        {
            Crop crop = new Crop();
            Wheat wheat = new Wheat();
            CropWatering cropWatering = new CropWatering();
            cropWatering.WaterSupply(crop);
            cropWatering.WaterSupply(wheat);
        }
        Output:
        I am working on type Crop
        I am working on type Wheat

To demostrate, compile-type, if we change the Wheat type to Crop, ‘new Wheat()’ is ignored and WaterSupply(Crop crop) is called for object crop and wheat.

        static void Main(string[] args)
        {
            Crop crop = new Crop();
            Crop wheat = new Wheat();
            CropWatering cropWatering = new CropWatering();
            cropWatering.WaterSupply(crop);
            cropWatering.WaterSupply(wheat);
        }
        Output:
        I am working on type Crop
        I am working on type Crop

Overriding

Overriding is run-time polymorphism. The methods/functions with same name and number/type of parameters are example of Overriding (Inheritance).

        class Crop
        {
            public virtual void CropName()
            {
                Console.WriteLine("Hey, My type is Crop");
            }
        }

        class Wheat : Crop
        {
            public override void CropName()
            {
                Console.WriteLine("Hey, My type is Wheat");
            }
        }
        static void Main(string[] args)
        {
            Crop crop = new Crop();
            Wheat wheat = new Wheat();
            crop.CropName();
            wheat.CropName();
        }
        Output:
        Hey, My type is Crop
        Hey, My type is Wheat

As type is determined at run-time thus new Crop() and new Wheat() is considered for object.

        static void Main(string[] args)
        {
            Crop crop = new Crop();
            Crop wheat = new Wheat();
            crop.CropName();
            wheat.CropName();
        }
        Output:
        Hey, My type is Crop
        Hey, My type is Wheat