
Polymorphism is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows objects of different types to be treated as objects of a common type. The word "polymorphism" comes from Greek, meaning "many forms." In simple terms, it enables a single method or property to behave differently based on the object it belongs to.
1. Types of Polymorphism in C#
a. Compile-Time Polymorphism (Static Polymorphism)
- What it is: Achieved using method overloading and operator overloading. The method to be executed is determined at compile time.
- Example in Real Life: A coffee machine that can make different types of coffee (espresso, latte, cappuccino) based on the button you press.
- Code Example:
class CoffeeMachine { public void MakeCoffee() => Console.WriteLine("Making regular coffee."); public void MakeCoffee(string type) => Console.WriteLine($"Making {type} coffee."); } CoffeeMachine machine = new CoffeeMachine(); machine.MakeCoffee(); // Regular coffee machine.MakeCoffee("Latte"); // Latte coffee
b. Runtime Polymorphism (Dynamic Polymorphism)
- What it is: Achieved using method overriding and interfaces. The method to be executed is determined at runtime.
- Example in Real Life: A universal remote control that works with different devices (TV, AC, Sound System). The same "power" button behaves differently depending on the device.
- Code Example:
class Device { public virtual void Power() => Console.WriteLine("Device is powered on/off."); } class TV : Device { public override void Power() => Console.WriteLine("TV is powered on/off."); } class AC : Device { public override void Power() => Console.WriteLine("AC is powered on/off."); } Device myDevice = new TV(); myDevice.Power(); // TV is powered on/off. myDevice = new AC(); myDevice.Power(); // AC is powered on/off.
2. Best Practices and Features
Best Practices
- Use Polymorphism for Extensibility: Design your code so that new types can be added without modifying existing code.
- Favor Interfaces Over Abstract Classes: Interfaces provide more flexibility for multiple inheritance.
- Avoid Overloading with Ambiguous Parameters: Ensure method overloads are clear and unambiguous.
- Use
virtual
andoverride
Keywords Properly: Clearly mark methods that can be overridden in derived classes. - Follow the Liskov Substitution Principle: Ensure derived classes can substitute their base classes without breaking functionality.
Features
- Code Reusability: Write generic code that works with multiple types.
- Flexibility: Easily extend functionality by adding new classes.
- Maintainability: Changes in one part of the code don’t affect other parts.
3. Pros and Cons
Pros
- Extensibility: New classes can be added without changing existing code.
- Code Reusability: Reduces redundancy by sharing common behavior.
- Readability: Makes code more intuitive and easier to understand.
- Flexibility: Supports dynamic behavior based on the object type.
Cons
- Complexity: Can make the code harder to understand for beginners.
- Performance Overhead: Runtime polymorphism (e.g., method overriding) can introduce slight performance overhead.
- Overuse: Excessive use of polymorphism can lead to overly complex designs.
4. Alternatives
- Conditional Logic: Use
if-else
orswitch
statements to handle different types. However, this can lead to messy and hard-to-maintain code. - Pattern Matching: In modern C#, use pattern matching to handle different types in a clean way.
switch (myDevice) { case TV tv: tv.Power(); break; case AC ac: ac.Power(); break; default: Console.WriteLine("Unknown device."); break; }
5. When to Use Polymorphism
- When You Have Multiple Related Types: Use polymorphism to handle objects of different types in a unified way.
- When You Need Extensibility: Use it when you expect to add new types in the future.
- When You Want to Reduce Code Duplication: Use it to share common behavior across classes.
- When You Need Dynamic Behavior: Use runtime polymorphism to decide behavior at runtime.
Advanced Code Example
using System; // Base class abstract class Shape { public abstract double Area(); // Abstract method } // Derived classes class Circle : Shape { public double Radius { get; set; } public Circle(double radius) => Radius = radius; public override double Area() => Math.PI * Radius * Radius; } class Rectangle : Shape { public double Width { get; set; } public double Height { get; set; } public Rectangle(double width, double height) { Width = width; Height = height; } public override double Area() => Width * Height; } class Program { static void Main() { Shape circle = new Circle(5); Shape rectangle = new Rectangle(4, 6); Console.WriteLine($"Area of Circle: {circle.Area()}"); // 78.54 Console.WriteLine($"Area of Rectangle: {rectangle.Area()}"); // 24 } }
Explanation of Advanced Code
- Abstract Class:
Shape
is an abstract class with an abstract methodArea()
. This enforces all derived classes to implement theArea()
method. - Polymorphism: The
Area()
method behaves differently forCircle
andRectangle
objects. - Extensibility: You can easily add new shapes (e.g.,
Triangle
) without modifying existing code.