Read the syntax
Polymorphism lets code hold a derived object in a base-class or interface reference. A virtual or interface method call uses the concrete object’s implementation at runtime.
The declared type limits which members are accessible at compile time; the runtime type determines an overridden method’s behavior. This allows one loop or method to work with several implementations.
Syntax
BaseType variable = new DerivedType();Examples
Runtime Polymorphism with Method Overriding
The same method call produces different behavior depending on the actual object type.
Animal[] animals = { new Dog(), new Cat(), new Animal() };
foreach (Animal a in animals)
{
a.MakeSound(); // calls the correct version for each actual object type
}
// Woof!
// Meow!
// Some generic sound
public class Animal
{
public virtual void MakeSound() => Console.WriteLine("Some generic sound");
}
public class Dog : Animal
{
public override void MakeSound() => Console.WriteLine("Woof!");
}
public class Cat : Animal
{
public override void MakeSound() => Console.WriteLine("Meow!");
}- The same method call produces different behavior depending on the actual object type.
- Polymorphism lets code hold a derived object in a base-class or interface reference. A virtual or interface method call uses the concrete object’s implementation at runtime.
- The Animal array holds Dog, Cat and Animal objects. The same MakeSound call prints Woof!, Meow! and the base sound in sequence.
Polymorphism with Interfaces
Treating different implementing classes uniformly through a shared interface type.
IShape[] shapes = { new Circle(3), new Square(4) };
foreach (IShape s in shapes)
{
Console.WriteLine($"Area: {s.Area():F2}");
}
public interface IShape
{
double Area();
}
public class Circle : IShape
{
private double _radius;
public Circle(double radius) => _radius = radius;
public double Area() => Math.PI * _radius * _radius;
}
public class Square : IShape
{
private double _side;
public Square(double side) => _side = side;
public double Area() => _side * _side;
}- Treating different implementing classes uniformly through a shared interface type.
- Polymorphism lets code hold a derived object in a base-class or interface reference. A virtual or interface method call uses the concrete object’s implementation at runtime.
- Both classes implement IShape.Area, but calculate it differently. The loop calls each implementation and formats the two areas to two decimal places.
Polymorphism in Method Parameters
A method that accepts the base type can work with any derived class, without needing to know the specific type.
void PrintPay(Employee e) // works with ANY Employee subclass
{
Console.WriteLine($"{e.Name}: ${e.CalculatePay()}");
}
PrintPay(new FullTime("John"));
PrintPay(new Contractor("Zain"));
public class Employee
{
public string Name;
public Employee(string name) => Name = name;
public virtual double CalculatePay() => 0;
}
public class FullTime : Employee
{
public FullTime(string name) : base(name) { }
public override double CalculatePay() => 5000;
}
public class Contractor : Employee
{
public Contractor(string name) : base(name) { }
public override double CalculatePay() => 3000;
}- A method that accepts the base type can work with any derived class, without needing to know the specific type.
- Polymorphism lets code hold a derived object in a base-class or interface reference. A virtual or interface method call uses the concrete object’s implementation at runtime.
- PrintPay accepts Employee and calls its virtual CalculatePay method. Passing FullTime and Contractor produces their respective pay amounts without branching on subtype.
Best practices
- Declare variables, parameters, and return types using the base type or interface when you want to write flexible, extensible code
- Rely on polymorphism instead of type-checking with "is" and manual casting where possible - let overridden methods handle the differences
- Remember polymorphism applies to virtual/overridden instance methods, not fields or static members, which are resolved based on the declared type instead
- Design base classes/interfaces around behavior that genuinely varies by subclass, so polymorphism adds real value rather than just ceremony
Runtime & versions
.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
C# language reference