Lesson 16 — Many Forms
Polymorphism
C# polymorphism works via virtual/override and is enhanced by pattern matching — making type-based dispatch concise and safe.
CSHARP — Polymorphism
Person[] group = {
new Learner("Thandi", 21, "C#", 74.5),
new Learner("Sipho", 24, "Java", 81.0),
new Facilitator("Ms Dube", 34, "Software Dev"),
new Learner("Lerato", 20, "SQL", 68.0)
};
// One loop — Java calls the right override for each object:
foreach (var person in group)
person.Introduce();
Pattern Matching
C# pattern matching is more powerful than Java's instanceof — it can match types, conditions, and values simultaneously.
CSHARP — Pattern matching
foreach (var person in group) {
// is-pattern: check type AND cast in one step:
if (person is Learner l)
Console.WriteLine($" Learner {l.Name}: {l.Course} | {l.Mark}%");
else if (person is Facilitator f)
Console.WriteLine($" Facilitator {f.Name}: {f.Specialisation}");
}
// Switch expression with type patterns:
static string Describe(Person p) => p switch {
Learner l when l.Mark >= 80 => $"{l.Name} — Distinction in {l.Course}",
Learner l => $"{l.Name} — studying {l.Course}",
Facilitator f => $"{f.Name} — facilitator",
_ => "Unknown person type"
};
foreach (var p in group)
Console.WriteLine(Describe(p));
Practice Task
Your Turn
Create a Shape hierarchy (Circle, Rectangle, Triangle all extending abstract Shape). Override ToString() on each. Store in Shape[]. Use a switch expression with type patterns to print the area of each with two decimal places. Calculate and print the total combined area.
Common Mistakes
- Forgetting virtual on the parent method.
- as without null check — returns null if cast fails, then NullReferenceException on next access.
- Direct cast without type check — throws InvalidCastException.
- Overusing pattern matching when a virtual method would be cleaner.
Professional Tip
Pattern matching is best for external dispatch — when you cannot add a virtual method to the type. For types you own, prefer virtual methods and polymorphism.
Mini Quiz
What does 'if (p is Learner l)' do in C#?
The is-pattern simultaneously checks the type and declares a variable of that type if the check passes. No explicit cast is needed.