1interface IShape { double Area(); }1abstract class Shape(string name) : IShape2public string Name { get; } = name;3public abstract double Area();4public string Info() => $"{Name}: {Area()}";Square: 9Rect: 1010heapName"Square"side3Name"Rect"w2h51class Square(double side) : Shape("Square")2public override double Area() => side * side;1class Rect(double w, double h) : Shape("Rect")2public override double Area() => w * h;1var sq = new Square(3);2var re = new Rect(2, 5);3Shape[] shapes = [sq, re];4foreach (var s in shapes)5 Console.WriteLine(s.Info());6IShape x = re;7Console.WriteLine(x.Area());Name · Info()Name · Info()newnewrefrefcall9Area()
Left: the types (IShape → Shape → Square, Rect)Right: the objects on the heap, Program.cs and the consoleTokens: inherited members, new objects, references, calls and resultsLeft: the types, as code cards. interface IShape is a contract; the abstract class Shape implements it and holds Name and Info(); Square and Rect inherit from Shape and override Area(). Right: the two objects on the heap, each with a Shape part and its own part, Program.cs, and the console. A call through a Shape or IShape reference runs the override of the object's real type: Square: 9, Rect: 10, 10. The code cards leave out each type's braces { } and the indentation. The full Program.cs is shown on this page; it builds with no warnings on .NET 8 (C# 12), which added primary constructors and collection expressions.

Inheritance

  1. Shape is a base class: it holds what every shape shares. Name stores a name, and Info() describes the shape. Because Shape is abstract, you cannot write new Shape(...); it exists only to be inherited from.

Override and polymorphism

Interfaces

What happens

// step 1/10 · base-class
1  abstract class Shape(string name) : IShape
2  public string Name { get; } = name;
3  public abstract double Area();
4  public string Info() => $"{Name}: {Area()}";

abstract   no objects of this exact type: new Shape("x") is error CS0144
shared     Name and Info() are written once, here

The code cards leave out each type's braces { } and the indentation. The full Program.cs is shown on this page; it builds with no warnings on .NET 8 (C# 12), which added primary constructors and collection expressions. Square(double side) is a primary constructor. Because Area() uses side, the compiler stores it in a hidden private field of the object; the figure simply calls that field side. Name is a property with its own hidden backing field.