C# Polymorphism


Polymorphism in C# is one of the core principles of object-oriented programming (OOP) that allows objects of different types to be treated as objects of a common super type. It enables a single interface to be used for a general class of actions, and the specific action is determined by the exact nature of the situation. Polymorphism can be achieved through two main techniques: compile-time polymorphism (also known as static polymorphism) and runtime polymorphism (also known as dynamic polymorphism).

1. Compile-Time Polymorphism

Compile-time polymorphism is achieved through method overloading and operator overloading.

Method Overloading

Method overloading allows multiple methods in the same class to have the same name but different parameters (type, number, or both). The appropriate method is determined at compile time based on the method signature.

Example of Method Overloading:

public class MathOperations { // Method to add two integers public int Add(int a, int b) { return a + b; } // Overloaded method to add three integers public int Add(int a, int b, int c) { return a + b + c; } // Overloaded method to add two doubles public double Add(double a, double b) { return a + b; } }

Operator Overloading

Operator overloading allows developers to define how operators behave with user-defined types (e.g., classes or structs).

Example of Operator Overloading:

public class Complex { public double Real { get; set; } public double Imaginary { get; set; } // Overloading the + operator public static Complex operator +(Complex c1, Complex c2) { return new Complex { Real = c1.Real + c2.Real, Imaginary = c1.Imaginary + c2.Imaginary }; } }

2. Runtime Polymorphism

Runtime polymorphism is achieved through method overriding. It allows a method to have different implementations based on the object that it is being called on. This is facilitated by inheritance and the use of the virtual and override keywords.

Method Overriding

When a derived class provides a specific implementation of a method that is already defined in its base class, it overrides the base class method. The decision about which method to call is made at runtime, depending on the object type.

Example of Method Overriding:

public class Animal { public virtual void MakeSound() { Console.WriteLine("Some sound"); } } public class Dog : Animal { public override void MakeSound() { Console.WriteLine("Woof!"); } } public class Cat : Animal { public override void MakeSound() { Console.WriteLine("Meow!"); } } public class Program { public static void Main() { Animal myAnimal; myAnimal = new Dog(); myAnimal.MakeSound(); // Outputs: Woof! myAnimal = new Cat(); myAnimal.MakeSound(); // Outputs: Meow! } }

Key Points About Polymorphism

  • Flexibility: Polymorphism allows for writing flexible and reusable code, as the same interface can be used for different underlying forms (data types).
  • Extensibility: New derived classes can be added without changing existing code, making systems easier to maintain and extend.
  • Loose Coupling: Polymorphism encourages a design where classes interact through interfaces or base classes rather than concrete implementations, promoting loose coupling.

Summary

Polymorphism in C# is a powerful feature that enables objects of different types to be treated as instances of a common base type. It enhances code flexibility, reusability, and maintainability through compile-time polymorphism (method and operator overloading) and runtime polymorphism (method overriding). By utilizing polymorphism, developers can create systems that are easier to extend and adapt to changing requirements.