Master C# Programming From Scratch

Clear, interactive, and structured coding lessons designed for absolute beginners.

Polymorphism in C#

Learn how one method, object, or interface can behave in different ways in C#.

What is Polymorphism?

Polymorphism is one of the four important pillars of Object-Oriented Programming (OOP).

The word polymorphism comes from two words: Poly means "many" and Morph means "forms".

Therefore, polymorphism means "one thing having many forms."

In C#, polymorphism allows the same method name or reference to perform different operations depending on the situation.

Simple Example: A person can behave differently in different situations. The same person can be a teacher in a classroom, a customer in a shop, and a parent at home.

Types of Polymorphism in C#

C# mainly supports two types of polymorphism:

Type Also Called Achieved Using
Compile-Time Polymorphism Static / Early Binding Method Overloading
Run-Time Polymorphism Dynamic / Late Binding Method Overriding

1. Compile-Time Polymorphism

Compile-time polymorphism is achieved using method overloading.

In method overloading, multiple methods have the same name but different parameters.

The compiler decides which method should be called during compilation.

Example: Method Overloading

C#
using System;
 
class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Add(int a, int b, int c)
    {
        return a + b + c;
    }

    public double Add(double a, double b)
    {
        return a + b;
    }
}

class Program
{
    static void Main()
    {
        Calculator calculator = new Calculator();

        Console.WriteLine(calculator.Add(10, 20));

        Console.WriteLine(calculator.Add(10, 20, 30));

        Console.WriteLine(calculator.Add(10.5, 20.5));
    }
}

Output

30
60
31

Program Explanation

Code Explanation
Calculator Class containing overloaded Add methods.
Add(int, int) Adds two integer values.
Add(int, int, int) Adds three integer values.
Add(double, double) Adds two decimal values.
calculator.Add() The compiler selects the correct method based on the arguments.

2. Run-Time Polymorphism

Run-time polymorphism is achieved using method overriding.

In method overriding, a child class provides its own implementation of a method that is already defined in the parent class.

The method that will execute is decided at runtime.

Important: Run-time polymorphism commonly uses virtual and override keywords.

Example: Method Overriding

C#
using System;
 
class Animal
{
    public virtual void Sound()
    {
        Console.WriteLine("Animal makes a sound");
    }
}

class Dog : Animal
{
    public override void Sound()
    {
        Console.WriteLine("Dog barks");
    }
}

class Cat : Animal
{
    public override void Sound()
    {
        Console.WriteLine("Cat meows");
    }
}

class Program
{
    static void Main()
    {
        Animal animal;

        animal = new Dog();
        animal.Sound();

        animal = new Cat();
        animal.Sound();
    }
}

Output

Dog barks
Cat meows

How This Program Works

  1. Animal contains the virtual Sound() method.
  2. Dog overrides the Sound() method.
  3. Cat also overrides the Sound() method.
  4. The variable animal is of type Animal.
  5. At runtime, it can refer to a Dog or Cat object.
  6. The appropriate overridden method is executed.

virtual and override Keywords

virtual Keyword

The virtual keyword allows a method in the parent class to be overridden by a child class.

override Keyword

The override keyword is used in the child class to provide a new implementation of the parent class method.

class Parent
{
    public virtual void Show()
    {
        Console.WriteLine("Parent Show");
    }
}

class Child : Parent
{
    public override void Show()
    {
        Console.WriteLine("Child Show");
    }
}

Parent Reference and Child Object

One of the most important concepts in runtime polymorphism is that a parent class reference can hold a child class object.

Animal animal = new Dog();

Here:

  • Animal is the reference type.
  • Dog is the actual object type.
  • The object is created at runtime.
  • The overridden method of Dog is executed.
Remember: Reference type decides what members are accessible, while the actual object type determines the overridden implementation that executes at runtime.

Example: Payment System 🤓🌍

Polymorphism is commonly used in real-world applications. For example, an application may support different payment methods.

Every payment method can have a common Pay() method, but each payment type can implement the method differently.

C#
using System;
 
class Payment
{
    public virtual void Pay()
    {
        Console.WriteLine("Processing payment");
    }
}

class CreditCardPayment : Payment
{
    public override void Pay()
    {
        Console.WriteLine("Payment through Credit Card");
    }
}

class UPIPayment : Payment
{
    public override void Pay()
    {
        Console.WriteLine("Payment through UPI");
    }
}

class Program
{
    static void Main()
    {
        Payment payment;

        payment = new CreditCardPayment();
        payment.Pay();

        payment = new UPIPayment();
        payment.Pay();
    }
}

Output

Payment through Credit Card
Payment through UPI

Why Polymorphism is Useful Here?

The application can work with the common Payment type instead of writing separate logic for every payment method.

Later, we can add another payment type such as CashPayment without changing the common payment structure.

Polymorphism with Multiple Objects

A parent class reference can be used to store multiple child objects. This becomes very useful when working with collections and arrays.

C#
using System;
 
class Animal
{
    public virtual void Sound()
    {
        Console.WriteLine("Animal sound");
    }
}

class Dog : Animal
{
    public override void Sound()
    {
        Console.WriteLine("Dog barks");
    }
}

class Cat : Animal
{
    public override void Sound()
    {
        Console.WriteLine("Cat meows");
    }
}

class Program
{
    static void Main()
    {
        Animal[] animals =
        {
            new Dog(),
            new Cat(),
            new Dog()
        };

        foreach (Animal animal in animals)
        {
            animal.Sound();
        }
    }
}

Output

Dog barks
Cat meows
Dog barks

This is a very important practical use of runtime polymorphism. A single collection can contain different child objects.

Method Overloading vs Method Overriding

Feature Overloading Overriding
Polymorphism Compile-Time Run-Time
Classes Usually same class Parent and child classes
Method Name Same Same
Parameters Must be different Must match overridden method
Keywords No special keyword required virtual / override commonly used
Decision Compiler Runtime

Polymorphism with Abstract Classes

Abstract classes can also be used to achieve runtime polymorphism. An abstract method does not contain an implementation in the parent class.

C#
using System;
 
abstract class Shape
{
    public abstract void Draw();
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing Circle");
    }
}

class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing Rectangle");
    }
}

class Program
{
    static void Main()
    {
        Shape shape;

        shape = new Circle();
        shape.Draw();

        shape = new Rectangle();
        shape.Draw();
    }
}

Output

Drawing Circle
Drawing Rectangle

Advantages of Polymorphism

  • Improves code reusability.
  • Reduces duplicate code.
  • Makes applications easier to maintain.
  • Supports flexible application design.
  • Helps implement common behavior with different implementations.
  • Makes large applications easier to extend.
  • Very useful in enterprise application development.

Common Mistakes

  1. Forgetting to use virtual in the parent method when using the traditional overriding approach.
  2. Using new when the intention is actually to override a virtual method.
  3. Confusing method overloading with method overriding.
  4. Trying to override a method that is not virtual, abstract, or already overridable.
  5. Creating unnecessary inheritance only to use polymorphism.

CIIT Practical Point

In real-world .NET applications, polymorphism is heavily used when designing scalable and maintainable systems.

For example, a project may have a common service or interface and multiple implementations for different business requirements.

This makes the application flexible and easier to extend when new functionality is added.

Important Interview Points

  • What is polymorphism?
  • What are the types of polymorphism in C#?
  • What is compile-time polymorphism?
  • What is run-time polymorphism?
  • What is method overloading?
  • What is method overriding?
  • What is the difference between overloading and overriding?
  • What is the purpose of virtual?
  • What is the purpose of override?
  • Can a parent reference hold a child object?
  • What is late binding?
  • How is polymorphism useful in real-world applications?

Summary

Polymorphism means one thing having many forms. It allows the same method or reference to behave differently depending on the situation.

C# supports compile-time polymorphism through method overloading and run-time polymorphism through method overriding.

Understanding polymorphism is essential for developing flexible, reusable, and maintainable object-oriented applications.

Practice Questions

  1. Create a Calculator class using method overloading.
  2. Create a Shape parent class and override Draw() in Circle and Rectangle.
  3. Create a Vehicle class and override Start() in Car and Bike.
  4. Create a Payment class and implement different payment types.
  5. Create an Employee parent class and override CalculateSalary() for different employees.