Polymorphism
Polymorphism
Section titled βPolymorphismβWhat it means
Section titled βWhat it meansβPolymorphism (βmany formsβ) means code can work with objects of a base type while actually running the correct derived typeβs behavior at runtime. In C#, this requires a base class method marked virtual (or abstract) and a derived class method marked override β calling the method through a base-typed reference still invokes the derived classβs version.
Examples
Section titled βExamplesβpublic class Shape{ public virtual double GetArea() => 0; public virtual string Describe() => $"A shape with area {GetArea():F2}";}
public class Circle : Shape{ public double Radius { get; set; } public override double GetArea() => Math.PI * Radius * Radius;}
public class Square : Shape{ public double Side { get; set; } public override double GetArea() => Side * Side;}
List<Shape> shapes = new(){ new Circle { Radius = 3 }, new Square { Side = 4 },};
foreach (var shape in shapes){ Console.WriteLine(shape.Describe()); // calls the CORRECT override for each, via the same Shape reference}Common mistake
Section titled βCommon mistakeβCasting to a base type and expecting the base implementation to run β polymorphism means the actual objectβs overridden method runs regardless of the referenceβs declared type, which surprises developers expecting C-style static dispatch.
Shape shape = new Circle { Radius = 5 };Console.WriteLine(shape.GetArea()); // Circle's GetArea() runs, NOT Shape's -- this is polymorphism working correctly
// This is often misunderstood as a "bug" by developers new to OOP,// but it's the entire point: the runtime type determines behavior, not the compile-time reference typeQuick practice
Section titled βQuick practiceβ-
What two keywords are required for polymorphic method dispatch to work between a base and derived class?
Answer
virtualon the base class method, andoverrideon the derived class's version. -
If you store a
Circleobject in a variable typed asShape, whichGetArea()implementation runs when you call it?Answer
Circle's overridden implementation β the actual runtime type of the object determines which override runs, not the declared type of the variable. -
Why is polymorphism useful when working with collections like
List<Shape>containing different shape subtypes?Answer
It lets you write one loop that calls the same method on every item, and each item automatically runs its own correct, type-specific behavior β no manual type-checking or branching required.