Skip to content

Intermediate · Inheritance, interfaces and records · topic 20 of 43 · 30 min

Interfaces: contracts for behaviour

Explanation

An interface is a contract: it lists members (methods, properties) that a class promises to have, without saying how. A class can implement many interfaces. Coding against an interface (like INotifier) lets you swap the real implementation, for example SMS for email or a fake for tests. .NET uses interfaces everywhere: IComparable for sorting, IDisposable for cleanup, IEnumerable for foreach.

Why interfaces?

A class can inherit from only one base class, but objects often have several unrelated abilities. A PDF report can be printed, emailed and saved. An interface describes one ability. Any class, from any family tree, can sign the contract by implementing it.

Think of it like this: An interface is like the standard Indian electric socket. The socket does not care whether you plug in a phone charger, a mixer or a lamp. It only demands the right plug shape (the contract). Any appliance with that plug works, and you can swap one for another.

Declaring and implementing

csharp
public interface INotifier
{
    bool Send(string to, string message);
}

public class SmsNotifier : INotifier
{
    public bool Send(string to, string message)
    {
        Console.WriteLine($"SMS to {to}: {message}");
        return true;
    }
}

public class EmailNotifier : INotifier
{
    public bool Send(string to, string message)
    {
        Console.WriteLine($"Email to {to}: {message}");
        return true;
    }
}
Interface names start with I by convention. Members are public by default and the class must implement all of them (error CS0535 if one is missing).

Programming to an interface

csharp
var service = new OrderService(new SmsNotifier());
service.PlaceOrder("Asha", "98xxxxxx10");

public class OrderService
{
    private readonly INotifier _notifier;
    public OrderService(INotifier notifier) => _notifier = notifier;

    public void PlaceOrder(string customer, string phone)
    {
        // ... save the order ...
        _notifier.Send(phone, $"Thanks {customer}, your order is confirmed");
    }
}
OrderService does not know or care which notifier it has. Passing the dependency in through the constructor is the heart of dependency injection (module 8) and makes testing easy (module 9).

Several interfaces at once

csharp
public interface IPrintable { string Print(); }
public interface IExportable { byte[] ToPdf(); }

public class Invoice : IPrintable, IExportable
{
    public string Print() => "Invoice #2041";
    public byte[] ToPdf() => Array.Empty<byte>();   // placeholder
}
A class may have one base class and any number of interfaces: class X : BaseClass, IOne, ITwo.

Built-in interface 1: IComparable<T>

Array.Sort and List.Sort need to know how to order your objects. Implement IComparable<T>: CompareTo returns a negative number if this comes first, 0 if equal, and a positive number if this comes after.

csharp
var list = new List<Student> { new("Ravi", 72), new("Asha", 91), new("Meena", 85) };
list.Sort();
foreach (var s in list) Console.WriteLine($"{s.Name} {s.Marks}");

public class Student : IComparable<Student>
{
    public string Name { get; }
    public int Marks { get; }
    public Student(string name, int marks) { Name = name; Marks = marks; }

    // higher marks first
    public int CompareTo(Student? other) => other is null ? -1 : other.Marks.CompareTo(Marks);
}
Shows Asha 91, Meena 85, Ravi 72. new("Ravi", 72) is a target-typed new: the type comes from the list.

Built-in interface 2: IDisposable and using

Some objects hold resources outside .NET's memory: open files, network connections, database connections. They implement IDisposable, which has one method, Dispose(), that releases the resource. A using statement calls Dispose automatically at the end, even if an exception happens.

csharp
using (var writer = new StreamWriter("log.txt"))
{
    writer.WriteLine("Started");
}   // writer.Dispose() runs here: the file is closed

using var reader = new StreamReader("log.txt");   // C# 8 using declaration
Console.WriteLine(reader.ReadLine());            // disposed at the end of the scope
Always wrap IDisposable objects in using.

Built-in interface 3: IEnumerable<T>

Anything that can be looped with foreach implements IEnumerable<T>: arrays, List<T>, Dictionary and more. LINQ (module 6) is built on it. Taking IEnumerable<T> as a parameter lets callers pass any of these.

Default interface methods (C# 8), briefly

An interface may give a member a default body, so adding a new member later does not break every existing class. It is mainly used by library authors. In your own code, keep interfaces small and simple.

Abstract class or interface?

Abstract classInterface
How many per classOneMany
Fields and constructorsYesNo instance fields or constructors
Shared codeYes, normal methodsOnly default methods (limited)
Meaning"is a kind of" with shared code"can do" an ability
Exampleabstract class Paymentinterface INotifier, IComparable<T>

Common mistakes and fixes

  • Huge interfaces with 20 members: classes must implement all of them. Split them into small, focused interfaces.
  • Forgetting public on the implementing method: the class method must be public to implement an interface member implicitly.
  • Not disposing: a StreamWriter that is never disposed may not write all its data. Use using.
  • Creating an interface for every class "just in case": add one when you have two implementations or need a fake for testing.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Interfaces: contracts for behaviour · 1/7

Interfaces

In this lesson you will define contracts with interfaces.

Prefer a video by a teacher? Find free videos on “C# interfaces explained IComparable IDisposable abstract class vs interface” on YouTube ↗

In real life: Switching SMS providers without touching business code

A clinic appointment app in Kochi sends reminders by SMS. When the SMS provider raises prices, the team writes a new class for a cheaper provider that implements the same IReminderSender interface. The appointment code does not change at all.

csharp
IReminderSender sender = new ProviderB();   // was: new ProviderA()
var reminders = new ReminderService(sender);
reminders.Remind("Meena", "9:30 AM");

public interface IReminderSender { void SendText(string to, string text); }

public class ProviderA : IReminderSender
{
    public void SendText(string to, string text) => Console.WriteLine($"[A] {to}: {text}");
}
public class ProviderB : IReminderSender
{
    public void SendText(string to, string text) => Console.WriteLine($"[B] {to}: {text}");
}

public class ReminderService
{
    private readonly IReminderSender _sender;
    public ReminderService(IReminderSender sender) => _sender = sender;
    public void Remind(string patient, string time) => _sender.SendText(patient, $"Your appointment is at {time}");
}
Shows [B] Meena: Your appointment is at 9:30 AM. Only one line changed to switch providers.

Practice (0/4 done)

Task 1 · Question

How many interfaces can one class implement?

Task 2 · Question

What does a using statement guarantee for an IDisposable object?

Task 3 · Question

a.CompareTo(b) returns a negative number. What does that mean for sorting?

Task 4 · Practice

Define an interface IDiscount with decimal Apply(decimal amount). Implement PercentDiscount (constructor takes a percent) and FlatDiscount (constructor takes rupees, never going below 0). Write a method Checkout(decimal amount, IDiscount discount) and call it with both.

Quick quiz

Question 1

1.What does an interface contain (in the usual case)?

Question 2

2.Which is a good reason to depend on an interface?

Question 3

3.Which interface makes foreach work on a type?

Question 4

4.A class implements an interface but misses one member. What happens?

Question 5

5.Which is TRUE?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does an interface contain (in the usual case)?

Answer: Member signatures that implementing classes must provide

An interface is a contract of members.

Which is a good reason to depend on an interface?

Answer: You can swap implementations (real, cheaper, fake for tests) without changing the caller

Loose coupling is the main benefit.

Which interface makes foreach work on a type?

Answer: IEnumerable<T>

foreach works on IEnumerable/IEnumerable<T>.

A class implements an interface but misses one member. What happens?

Answer: Compile error CS0535

Every interface member must be implemented.

Which is TRUE?

Answer: A class can inherit one class and implement many interfaces

Single class inheritance, multiple interfaces.

How many interfaces can a class implement?Related

Answer: Many

Multiple interface implementation is allowed.

From Interfaces

What is an extension method?Related

Answer: A static method whose first parameter uses this, callable like an instance method

LINQ methods are extension methods on IEnumerable<T>.

From The C# and .NET interview questions asked most often

Can an interface function have a default body in Kotlin?Related

Answer: Yes

Interfaces can provide default implementations.

From Inheritance and interfaces

Can an abstract class have a constructor and data members?Related

Answer: Yes; it just cannot be instantiated on its own

Abstract only means "cannot be created directly". It may still hold shared data and constructors for derived classes.

From Abstract classes, interfaces and good class design

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Inheritance, interfaces and records” before its exam: Records and pattern matching.
  2. Module 5 exam: Inheritance, interfaces and records · 13 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Collections, generics and LINQ. 43 topics left in the course before the final exam.

← Previous: Abstract classes and polymorphism