Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects to take on many forms. In C#, it provides the ability to define methods in a base class and override or implement them in derived classes. This makes your code more flexible, reusable, and easier to maintain.
In this post, we’ll explore the essence of polymorphism, dive into method overriding, interfaces, and abstract classes, and learn how to use them effectively in C#.
The term polymorphism comes from the Greek words poly (many) and morph (forms). In programming, it means that a single interface or method can represent different types or behaviors. Polymorphism is implemented in two primary ways in C#:
This post focuses on runtime polymorphism.
Method overriding allows a derived class to provide a specific implementation of a method defined in a base class. This is done using the virtual
keyword in the base class and the override
keyword in the derived class.
// Base class
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Animal makes a sound.");
}
}
// Derived class
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Dog barks.");
}
}
public class Cat : Animal
{
public override void Speak()
{
Console.WriteLine("Cat meows.");
}
}
// Using polymorphism
Animal myAnimal;
myAnimal = new Dog();
myAnimal.Speak(); // Output: Dog barks.
myAnimal = new Cat();
myAnimal.Speak(); // Output: Cat meows.
Here, the Speak
method behaves differently depending on the type of object.
Abstract classes serve as a blueprint for derived classes. You cannot instantiate an abstract class, but you can define abstract methods that must be implemented in derived classes.
public abstract class Shape
{
public abstract double CalculateArea();
public void DisplayInfo()
{
Console.WriteLine("This is a shape.");
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public override double CalculateArea()
{
return Math.PI * Radius * Radius;
}
}
public class Rectangle : Shape
{
public double Length { get; set; }
public double Width { get; set; }
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
public override double CalculateArea()
{
return Length * Width;
}
}
// Using abstract classes
Shape myShape = new Circle(5);
Console.WriteLine(myShape.CalculateArea()); // Output: 78.54
myShape = new Rectangle(4, 6);
Console.WriteLine(myShape.CalculateArea()); // Output: 24
In this example, the CalculateArea
method is defined in the Shape
class but implemented differently in Circle
and Rectangle
.
An interface defines a contract that classes must adhere to. Unlike abstract classes, interfaces do not provide any implementation; they only declare members that implementing classes must define.
public interface IShape
{
double CalculateArea();
void DisplayInfo();
}
public class Circle : IShape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public double CalculateArea()
{
return Math.PI * Radius * Radius;
}
public void DisplayInfo()
{
Console.WriteLine("This is a circle.");
}
}
public class Rectangle : IShape
{
public double Length { get; set; }
public double Width { get; set; }
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
public double CalculateArea()
{
return Length * Width;
}
public void DisplayInfo()
{
Console.WriteLine("This is a rectangle.");
}
}
// Using interfaces
IShape shape = new Circle(5);
shape.DisplayInfo(); // Output: This is a circle.
Console.WriteLine(shape.CalculateArea()); // Output: 78.54
shape = new Rectangle(4, 6);
shape.DisplayInfo(); // Output: This is a rectangle.
Console.WriteLine(shape.CalculateArea()); // Output: 24
Interfaces are ideal for scenarios where multiple classes share common functionality but do not share a common base class.
Feature | Abstract Class | Interface |
---|---|---|
Instantiation | Cannot be instantiated | Cannot be instantiated |
Inheritance | Single inheritance | Multiple inheritance allowed |
Member Implementation | Can include method implementations | Only declarations (no implementations in C# < 8.0) |
Usage | Use when classes share a common base | Use for unrelated classes with shared behavior |
public void PrintShapeInfo(IShape shape) { shape.DisplayInfo(); Console.WriteLine($"Area: {shape.CalculateArea()}"); }
Polymorphism is a powerful feature that enhances the flexibility and scalability of your applications. By understanding method overriding, interfaces, and abstract classes, you can design clean, modular, and extensible code. Practice applying polymorphism in real-world scenarios to harness its full potential in your development projects.
Encapsulation and abstraction are two pillars of object-oriented programming (OOP) that play a vital role…
Inheritance is a cornerstone of object-oriented programming (OOP) and one of its most powerful features.…
In the world of C# and object-oriented programming (OOP), classes and objects form the backbone…
In modern C# programming, working with data collections is a common task. Understanding how to…
Exception handling is a critical part of writing robust and maintainable C# applications. It allows…
One of the common questions among Docker users is whether Docker containers consume disk space.…