Skip to main content
C# Fundamentals for Beginners to Advanced
CHAPTER 16 Beginner

Polymorphism in C#

Updated: May 17, 2026
5 min read

# CHAPTER 16

Polymorphism in C#

1. Introduction

Polymorphism comes from Greek, meaning "many forms." In C#, it allows us to perform a single action in different ways. It is the magic that allows a video game engine to tell an array of 1,000 different entities to Update(), and each entity knows exactly how to update itself based on its specific class.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define Polymorphism in OOP.
  • Understand Compile-time Polymorphism (Method Overloading).
  • Understand Runtime Polymorphism (Method Overriding).
  • Use Base class variables to hold Derived class objects.

3. Types of Polymorphism

Polymorphism in C# takes two main forms:
  1. 1. Compile-time Polymorphism (Static Binding): Achieved through Method Overloading. The compiler knows exactly which method to call when it builds the application.
  1. 2. Runtime Polymorphism (Dynamic Binding): Achieved through Inheritance and Method Overriding (virtual/override). The application decides which method to call *while it is running* based on the actual object type.

4. Compile-time Polymorphism (Recap)

We saw this in Chapter 11. It's when multiple methods have the same name but different parameters.
csharp
123456
class Printer
{
    public void Print(int i) { Console.WriteLine($"Printing int: {i}"); }
    public void Print(string s) { Console.WriteLine($"Printing string: {s}"); }
}
// The compiler knows which one to call at compile time based on the argument.

5. Runtime Polymorphism (The Real Magic)

Let's look at the true power of OOP. A Base class variable is legally allowed to hold a Derived class object!
csharp
123456789101112131415161718192021222324252627282930313233343536373839404142
using System;
using System.Collections.Generic;

class Animal
{
    public virtual void Speak() { Console.WriteLine("Animal sound"); }
}

class Dog : Animal
{
    public override void Speak() { Console.WriteLine("Woof!"); }
}

class Cat : Animal
{
    public override void Speak() { Console.WriteLine("Meow!"); }
}

class Program
{
    static void Main()
    {
        // A Base class variable pointing to a Derived object!
        Animal myPet = new Dog();
        
        // Output: "Woof!"
        // The CLR checks at runtime what myPet *actually* is, and calls Dog's method.
        myPet.Speak(); 
        
        // Let's create an array of Base class objects
        List<Animal> zoo = new List<Animal>();
        zoo.Add(new Dog());
        zoo.Add(new Cat());
        zoo.Add(new Animal());

        // We can treat them all identically!
        foreach (Animal a in zoo)
        {
            a.Speak(); // Output: Woof!, Meow!, Animal sound
        }
    }
}

6. Why is this useful?

Imagine a Drawing app. You have an abstract concept of a Shape with a Draw() method. You have specific classes: Circle, Square, Triangle. Without polymorphism, your code would look like: if (type == "Circle") { drawCircle(); } else if (type == "Square") { drawSquare(); }

With polymorphism, you just put them all in a List<Shape> and loop through them calling shape.Draw(). If you add a Hexagon class later, you don't have to change the loop code at all! The system automatically scales.

7. OOP and Memory Explanation

How does the runtime know which method to call? C# uses a mechanism called the Virtual Method Table (VTable). When a class has virtual methods, the CLR creates a hidden table of function pointers. When myPet.Speak() is called, the CLR looks at the object in Heap memory, finds its VTable, and dynamically resolves the pointer to the Dog.Speak() method instead of the Animal.Speak() method.

8. Common Mistakes

  • Forgetting override: If you forget the override keyword in the child class (and optionally use new), you perform Method Hiding. In this case, Animal myPet = new Dog(); myPet.Speak(); will output "Animal sound", entirely defeating runtime polymorphism! Always use override.

9. Best Practices

  • Use polymorphism to eliminate massive if/else and switch statements that check an object's type.

10. Exercises

  1. 1. Create a Vehicle base class with a virtual StartEngine() method.
  1. 2. Create Car and Motorcycle derived classes that override StartEngine().
  1. 3. In Main(), create an array of Vehicle containing both cars and motorcycles, and loop through them calling StartEngine().

11. MCQs with Answers

Question 1

What does Polymorphism mean?

Question 2

Method Overloading is an example of:

Question 3

Method Overriding (virtual/override) is an example of:

Q4. Can a variable of type BaseClass hold an object of type DerivedClass? a) Yes (e.g., Animal a = new Dog();) b) No Answer: a) Yes

Q5. Can a variable of type DerivedClass hold an object of type BaseClass? a) Yes b) No (e.g., Dog d = new Animal(); is invalid) Answer: b) No

Question 6

What happens if you call a virtual method on a Base reference holding a Derived object?

Question 7

What hidden structure does the CLR use to resolve virtual method calls at runtime?

Question 8

What happens if you forget the override keyword in the derived class?

Question 9

Polymorphism is excellent for eliminating which type of code?

Q10. Is polymorphism unique to C#? a) Yes b) No, it is a core pillar of all OOP languages like Java, C++, and Python Answer: b) No, it is a core pillar of all OOP languages

12. Interview Questions

  • Q: Differentiate between Compile-time and Runtime Polymorphism. Give examples of each.
  • Q: Explain the "Liskov Substitution Principle" (The 'L' in SOLID) in the context of Polymorphism. (Answer: Objects of a superclass shall be replaceable with objects of its subclasses without breaking the application).

13. Summary

Polymorphism allows objects of different classes to be treated as objects of a common Base class. Through the power of virtual and override methods, the C# runtime dynamically ensures that the correct, specific behavior is executed, making your code highly scalable and maintainable.

14. Next Chapter Recommendation

In Chapter 17: Encapsulation and Abstraction, we will revisit the remaining pillars of OOP, learning how to properly protect our data and hide unnecessary complexity from other developers.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·