📝 Lesson 5.2: Interfaces
Inheritance links classes by what they are. Interfaces link classes by what they can do. An interface is a contract — a promise that a class provides certain abilities, no matter what kind of class it is.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Explain what an interface is and how it differs from a class
- Define an interface and implement it in a class
- Implement multiple interfaces in one class
- Write code that depends on an interface, not a concrete type
- Decide when to use an interface vs. inheritance
Estimated Time: 60 minutes
Project: Define capabilities as interfaces and implement them across different classes.
In This Lesson
What Is an Interface?
An interface defines a set of members (methods and properties) that a class promises to provide — but it contains no implementation itself. It's a pure contract: "any class that implements me will have these abilities."
📖 Definition
Interface: a contract listing members a class must implement. The interface says what must exist; each class decides how.
A great analogy is a job description. It lists the responsibilities ("must be able to take payment," "must be able to open the store") without saying who does them or how. Different people (classes) can each fulfill the same job description in their own way.
The key difference from inheritance: a class can inherit from only one base class, but it can implement many interfaces — and interfaces cut across unrelated class families.
Play()"] --> A["MusicTrack"] I --> B["VideoClip"] I --> C["Podcast"] style I fill:#eff6ff,stroke:#3b82f6,stroke-width:2px style A fill:#e8f5e9,stroke:#4CAF50,stroke-width:2px style B fill:#e8f5e9,stroke:#4CAF50,stroke-width:2px style C fill:#e8f5e9,stroke:#4CAF50,stroke-width:2px
Defining and Implementing
You declare an interface with the interface keyword. By strong convention, interface names start with a capital I (e.g. IPlayable). The members have no body — just their signatures:
interface IPlayable
{
void Play(); // no body — just the promise
void Stop();
}
💡 Notice what's missing
No public keyword (interface members are public by default), and no method bodies. An interface only lists what members exist, never how they work.
A class implements an interface using the same : syntax as inheritance, and must provide a real body for every member the interface requires:
class MusicTrack : IPlayable
{
public string Title { get; set; }
public void Play()
{
Console.WriteLine($"♪ Playing '{Title}'");
}
public void Stop()
{
Console.WriteLine($"■ Stopped '{Title}'");
}
}
MusicTrack song = new MusicTrack { Title = "C# Blues" };
song.Play(); // ♪ Playing 'C# Blues'
song.Stop(); // ■ Stopped 'C# Blues'
⚠️ You must implement everything
If a class claims to implement IPlayable but forgets Stop(), the code won't compile. That's the whole point of a contract: the compiler guarantees every promised member actually exists.
Programming to an Interface
Here's where interfaces become powerful. You can write code that works with the interface type instead of any specific class. That code then works with any class that implements the interface — including ones you haven't written yet.
class Podcast : IPlayable
{
public void Play() { Console.WriteLine("▶ Playing a podcast episode"); }
public void Stop() { Console.WriteLine("■ Podcast paused"); }
}
// This method accepts ANY IPlayable — song, podcast, anything
void PlayItTwice(IPlayable item)
{
item.Play();
item.Stop();
item.Play();
}
PlayItTwice(new MusicTrack { Title = "C# Blues" });
PlayItTwice(new Podcast());
Output:
♪ Playing 'C# Blues'
■ Stopped 'C# Blues'
♪ Playing 'C# Blues'
▶ Playing a podcast episode
■ Podcast paused
▶ Playing a podcast episode
You can also hold different concrete types in one List of the interface type — even though MusicTrack and Podcast are otherwise unrelated:
List<IPlayable> playlist = new List<IPlayable>
{
new MusicTrack { Title = "C# Blues" },
new Podcast()
};
foreach (IPlayable item in playlist)
{
item.Play(); // each runs its own version
}
✅ Why this matters
Depending on an interface instead of a concrete class makes your code flexible and future-proof. Add a new VideoClip : IPlayable next year and PlayItTwice works with it unchanged. This is one of the most important design ideas in professional C#.
Implementing Multiple Interfaces
A class can only inherit one base class, but it can implement as many interfaces as it needs — just separate them with commas. This lets you compose capabilities freely:
interface IPlayable
{
void Play();
}
interface IDownloadable
{
void Download();
}
// A class can promise BOTH capabilities
class MusicTrack : IPlayable, IDownloadable
{
public string Title { get; set; }
public void Play() { Console.WriteLine($"♪ Playing '{Title}'"); }
public void Download() { Console.WriteLine($"⬇ Downloading '{Title}'"); }
}
MusicTrack song = new MusicTrack { Title = "C# Blues" };
song.Play(); // works because it's IPlayable
song.Download(); // works because it's IDownloadable
💡 If a base class is also involved
You can inherit a base class and implement interfaces at the same time. List the base class first, then the interfaces:
class MusicTrack : MediaItem, IPlayable, IDownloadable
{
// ...
}
Here MediaItem is the single base class; IPlayable and IDownloadable are interfaces.
Interface vs. Inheritance
Both use the : syntax, so how do you choose? It comes down to "is-a" versus "can-do".
| Inheritance (base class) | Interface | |
|---|---|---|
| Expresses | "is-a" (a Dog is an Animal) | "can-do" (a Dog can be IComparable) |
| Provides code? | Yes — real methods and data to inherit | No — just the contract (members to implement) |
| How many? | One base class only | Many interfaces at once |
| Best for | Sharing common implementation among related types | Sharing a capability across unrelated types |
💡 A quick test: If you'd say a class is a kind of something → inheritance. If you'd say a class is able to do something → interface. AFileLoggeris aLogger(inheritance), but many unrelated things can beIDisposable(interface).
✅ They work together
You don't have to pick just one. Real designs commonly use a base class for shared behavior and interfaces for cross-cutting capabilities — exactly the combined form shown above.
Interfaces in .NET
You've already been using interfaces without knowing it. .NET is full of them, and recognizing the common ones helps you read real code:
| Interface | The capability it promises |
|---|---|
IEnumerable<T> | Can be looped over with foreach (arrays and List<T> implement it) |
IComparable<T> | Can be compared and therefore sorted |
IDisposable | Holds resources that need cleaning up (used with using) |
For example, implementing IComparable<T> teaches C# how to sort your own type:
class Player : IComparable<Player>
{
public string Name { get; set; }
public int Score { get; set; }
// Contract from IComparable: define how two players compare
public int CompareTo(Player other)
{
return Score.CompareTo(other.Score); // sort by score
}
}
Because Player now honors the IComparable<Player> contract, built-in tools like list.Sort() know how to order players — you plugged your class into machinery .NET already had.
Exercise & Quiz
🏋️ Exercise: Notifications by Contract
Objective: Define an interface and implement it across unrelated classes, then program to the interface.
Instructions:
- Create a new project called
Notify. - Define an interface
INotifierwith one method:void Send(string message). - Create two classes that implement it:
EmailNotifier(prints "Email: ...") andSmsNotifier(prints "SMS: ..."). - Write a method
void Alert(INotifier notifier, string message)that callsnotifier.Send(message). - Call
Alertwith each notifier. Bonus: put both notifiers in aList<INotifier>and loop to send the same message through all of them.
Starter Code:
Alert(new EmailNotifier(), "Server is down!");
Alert(new SmsNotifier(), "Server is down!");
void Alert(INotifier notifier, string message)
{
notifier.Send(message);
}
interface INotifier
{
void Send(string message);
}
// TODO: EmailNotifier : INotifier
// TODO: SmsNotifier : INotifier
💡 Hint
Each class needs public void Send(string message) with its own Console.WriteLine. Because Alert takes an INotifier, it doesn't care which class you pass — that's the power of the contract.
✅ Solution
Alert(new EmailNotifier(), "Server is down!");
Alert(new SmsNotifier(), "Server is down!");
// Bonus: broadcast through all notifiers
List<INotifier> channels = new List<INotifier>
{
new EmailNotifier(),
new SmsNotifier()
};
foreach (INotifier channel in channels)
{
channel.Send("Nightly backup complete.");
}
void Alert(INotifier notifier, string message)
{
notifier.Send(message);
}
interface INotifier
{
void Send(string message);
}
class EmailNotifier : INotifier
{
public void Send(string message)
{
Console.WriteLine($"Email: {message}");
}
}
class SmsNotifier : INotifier
{
public void Send(string message)
{
Console.WriteLine($"SMS: {message}");
}
}
Output:
Email: Server is down!
SMS: Server is down!
Email: Nightly backup complete.
SMS: Nightly backup complete.
🎯 Quick Quiz
Question 1: What does an interface contain?
Question 2: How many interfaces can one class implement?
Question 3: When should you prefer an interface over inheritance?
Summary
🎉 Key Takeaways
- An interface is a contract: it lists members a class must provide, with no implementation of its own.
- Name interfaces with a leading I (
IPlayable); implement withclass C : IPlayableand provide every member. - Programming to an interface — accepting/holding the interface type — makes code flexible and future-proof.
- A class can implement many interfaces (and optionally one base class), composing capabilities.
- Inheritance = "is-a" (shares code); interface = "can-do" (shares a capability across unrelated types). .NET uses interfaces like
IEnumerable<T>andIComparable<T>everywhere.
📚 Additional Resources
🚀 What's Next?
You've now met both ways to relate classes: inheritance and interfaces. In the final lesson, Lesson 5.3: Polymorphism and Abstract Classes, we bring it all together — writing code that treats many different types uniformly, and using abstract classes to define partial blueprints.
🎉 Contracts mastered!
Interfaces are the key to flexible, professional design. One lesson to go — let's tie it all together.