Interfaces
Contracts that any class can sign: define interfaces, implement several at once, program against them, and choose between interfaces and abstract classes.
public interface IExportable // by convention, names start with I{ string ToIfc(); // a promise: no body, no access modifier needed} public class Bolt : IExportable // "Bolt implements IExportable"{ public string Grade { get; init; } = "8.8"; public string ToIfc() => $"IFCMECHANICALFASTENER('{Grade}')";} public class Beam : StructuralMember, IExportable // base class first, then interfaces{ public string ToIfc() => $"IFCBEAM('{Mark}')";}Programming to the interface
static void ExportAll(IEnumerable<IExportable> items){ foreach (IExportable item in items) Console.WriteLine(item.ToIfc());} var model = new List<IExportable>{ new Beam { Mark = "B1" }, new Bolt { Grade = "10.9" }};ExportAll(model);IFCBEAM('B1')
IFCMECHANICALFASTENER('10.9')ExportAll doesn’t know or care about beams or bolts. It only needs “something that can ToIfc()”. New exportable classes will work with it without changing a line. This is how large applications stay flexible.
Several interfaces at once
public interface IWeighable { double WeightKg { get; } }public interface IPrintable { void Print(); } public class Beam : StructuralMember, IExportable, IWeighable, IPrintable{ public double WeightKg => Length * 42.2; public string ToIfc() => $"IFCBEAM('{Mark}')"; public void Print() => Console.WriteLine($"{Mark}: {WeightKg:F1} kg");}Interfaces you already use
| Interface | Capability | Enables |
|---|---|---|
IEnumerable<T> | foreach, LINQ | |
IComparable<T> | List.Sort(), Array.Sort() | |
IDisposable | using statements | |
IEquatable<T> | Equals, dictionary keys |
public class Beam : IComparable<Beam>{ public string Mark { get; init; } = ""; public double Length { get; init; } public int CompareTo(Beam? other) => Length.CompareTo(other?.Length ?? 0);} var beams = new List<Beam> { new() { Mark = "B1", Length = 7 }, new() { Mark = "B2", Length = 4 } };beams.Sort(); // uses CompareToConsole.WriteLine(string.Join(", ", beams.Select(b => b.Mark)));B2, B1
Interface or abstract class?
| Interface | Abstract class | |
|---|---|---|
IDiscountable with a method decimal ApplyDiscount(decimal price). Implement it in StudentDiscount (20% off) and FestivalDiscount (₹500 off, never below 0). Write a method that takes an IDiscountable and prints the final price of ₹2000.
Show the solution
public interface IDiscountable{ decimal ApplyDiscount(decimal price);} public class StudentDiscount : IDiscountable{ public decimal ApplyDiscount(decimal price) => price * 0.8m;} public class FestivalDiscount : IDiscountable{ public decimal ApplyDiscount(decimal price) => Math.Max(0, price - 500);} static void Show(IDiscountable d) => Console.WriteLine($"{d.GetType().Name}: {d.ApplyDiscount(2000m)}"); Show(new StudentDiscount());Show(new FestivalDiscount());StudentDiscount: 1600.0 FestivalDiscount: 1500
Remember
An interface is a contract of members a class promises to implement. One base class, many interfaces: class Beam : Member, IExportable, IPrintable.Write methods that accept interfaces so any implementing class works. Interface = capability across families; abstract class = shared code within a family.