Interfaces & Abstract Classes
Both define contracts that other classes must fulfill, but they serve different purposes.
Interfaces
An interface defines what a class must do, not how. A class can implement multiple interfaces:
public interface IShape
{
double Area();
double Perimeter();
string Name { get; }
}
public class Circle : IShape
{
public double Radius { get; set; }
public string Name => "Circle";
public Circle(double radius) => Radius = radius;
public double Area() => Math.PI * Radius * Radius;
public double Perimeter() => 2 * Math.PI * Radius;
}
public class Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public string Name => "Rectangle";
public Rectangle(double w, double h) { Width = w; Height = h; }
public double Area() => Width * Height;
public double Perimeter() => 2 * (Width + Height);
}
Using the Interface
List<IShape> shapes = new()
{
new Circle(5),
new Rectangle(4, 6)
};
foreach (IShape shape in shapes)
{
Console.WriteLine($"{shape.Name}: Area={shape.Area():F2}");
}
Abstract Classes
An abstract class can provide shared implementation along with abstract members:
public abstract class Vehicle
{
public string Make { get; set; }
public int Year { get; set; }
protected Vehicle(string make, int year)
{
Make = make;
Year = year;
}
// Must be implemented by subclasses
public abstract double FuelEfficiency();
// Shared implementation
public string Summary()
{
return $"{Year} {Make} — {FuelEfficiency():F1} mpg";
}
}
public class Car : Vehicle
{
public Car(string make, int year) : base(make, year) { }
public override double FuelEfficiency() => 30.5;
}
When to Use Which
| Feature | Interface | Abstract Class |
|---|---|---|
| Multiple inheritance | Yes | No |
| Shared code | Default methods (C# 8+) | Yes |
| Fields | No | Yes |
| Constructors | No | Yes |
Rule of thumb: Use interfaces to define capabilities (ISerializable, IComparable). Use abstract classes to share code among related classes.