Chapter 14: Interfaces
1. What is an Interface? (Super Simple Analogy)
Think of an interface like a contract or a remote control standard:
- The interface says: “If you want to be a part of my club, you must have these buttons/methods: Play(), Stop(), Pause()”
- Any device that implements this interface (TV, Music Player, DVD Player, Game Console) must provide its own version of Play(), Stop(), Pause()
- You can use any of these devices with the same remote (same code) – because they all follow the same contract
Key points:
- Interfaces define WHAT a class must do (methods, properties, events)
- They do NOT say HOW to do it – no implementation (except default methods in C# 8+)
- Classes can implement multiple interfaces → this is C#’s way of doing multiple inheritance (safely!)
2. Defining an Interface
Syntax:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
interface IName { // Methods (no body!) void DoSomething(); // Properties string Name { get; set; } // Events (rare) event EventHandler SomethingHappened; // Indexers (rare) int this[int index] { get; set; } } |
Naming convention (very important):
- Interface names start with I (capital i) → INotification, IRepository, ILogger
Real example – Notification contract
|
0 1 2 3 4 5 6 7 8 9 10 |
interface INotifier { void Send(string message); bool IsEnabled { get; set; } } |
3. Implementing an Interface
Any class that implements the interface must provide all the members!
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
class EmailNotifier : INotifier { public bool IsEnabled { get; set; } = true; public void Send(string message) { if (IsEnabled) Console.WriteLine($"📧 Email sent: {message}"); else Console.WriteLine("Email notifications are disabled."); } } class SmsNotifier : INotifier { public bool IsEnabled { get; set; } = true; public void Send(string message) { if (IsEnabled) Console.WriteLine($"📱 SMS sent: {message}"); else Console.WriteLine("SMS notifications are disabled."); } } class PushNotifier : INotifier { public bool IsEnabled { get; set; } = true; public void Send(string message) { if (IsEnabled) Console.WriteLine($"🔔 Push notification: {message}"); else Console.WriteLine("Push notifications are disabled."); } } |
Polymorphic usage – same code for all notifiers
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
INotifier[] notifiers = new INotifier[] { new EmailNotifier(), new SmsNotifier(), new PushNotifier() }; foreach (INotifier notifier in notifiers) { notifier.IsEnabled = true; notifier.Send("Your order has been shipped! 🚚"); } |
Output:
|
0 1 2 3 4 5 6 7 8 |
📧 Email sent: Your order has been shipped! 🚚 📱 SMS sent: Your order has been shipped! 🚚 🔔 Push notification: Your order has been shipped! 🚚 |
4. Multiple Inheritance via Interfaces (C#’s Superpower!)
Unlike classes (you can inherit only one base class), a class can implement many interfaces!
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
interface IPrintable { void Print(); } interface ISavable { void Save(string filePath); } interface IShareable { void Share(string platform); } class Document : IPrintable, ISavable, IShareable { public string Content { get; set; } public void Print() { Console.WriteLine($"Printing: {Content}"); } public void Save(string filePath) { Console.WriteLine($"Saving document to {filePath}"); } public void Share(string platform) { Console.WriteLine($"Sharing document on {platform}"); } } |
Usage:
|
0 1 2 3 4 5 6 7 8 9 10 |
Document doc = new Document { Content = "My important report" }; doc.Print(); // Printing... doc.Save("report.pdf"); // Saving... doc.Share("WhatsApp"); // Sharing... |
5. Default Interface Methods (C# 8.0+) – Huge Game-Changer!
Since C# 8, interfaces can have default implementations – like a base method that children can use or override.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
interface ILogger { void Log(string message); // Default implementation (optional override) void LogError(string message) { Console.ForegroundColor = ConsoleColor.Red; Log($"ERROR: {message}"); Console.ResetColor(); } } class ConsoleLogger : ILogger { public void Log(string message) { Console.WriteLine($"[LOG] {message}"); } // We can override the default if we want // public void LogError(string message) { ... } } class FileLogger : ILogger { public void Log(string message) { // Simulate writing to file Console.WriteLine($"[FILE] {message}"); } // Using the default LogError() } |
Usage:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
ILogger logger = new ConsoleLogger(); logger.Log("Normal message"); logger.LogError("Critical failure!"); // Uses default implementation logger = new FileLogger(); logger.Log("Normal message"); logger.LogError("Critical failure!"); // Also uses default |
Mini-Project: Payment Gateway System with Interfaces
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
interface IPaymentProcessor { void ProcessPayment(decimal amount); bool Refund(decimal amount); // Default method (C# 8+) void LogTransaction(decimal amount, string type = "Payment") { Console.WriteLine($"[{type}] Transaction of ₹{amount:N2} logged."); } } class RazorpayProcessor : IPaymentProcessor { public void ProcessPayment(decimal amount) { Console.WriteLine($"Razorpay: Processing ₹{amount:N2}..."); LogTransaction(amount); } public bool Refund(decimal amount) { Console.WriteLine($"Razorpay: Refunding ₹{amount:N2}..."); return true; } } class PaytmProcessor : IPaymentProcessor { public void ProcessPayment(decimal amount) { Console.WriteLine($"Paytm: Charging ₹{amount:N2} via UPI..."); LogTransaction(amount); } public bool Refund(decimal amount) { Console.WriteLine($"Paytm: Processing refund of ₹{amount:N2}..."); return true; } } class CashOnDelivery : IPaymentProcessor { public void ProcessPayment(decimal amount) { Console.WriteLine($"COD: Order placed for ₹{amount:N2}. Pay on delivery."); LogTransaction(amount, "COD Order"); } public bool Refund(decimal amount) { Console.WriteLine("COD: No refund possible."); return false; } } // Usage IPaymentProcessor[] gateways = new IPaymentProcessor[] { new RazorpayProcessor(), new PaytmProcessor(), new CashOnDelivery() }; foreach (var gateway in gateways) { gateway.ProcessPayment(1499.99m); gateway.Refund(1499.99m); Console.WriteLine(); } |
Summary – What We Learned Today
- Interface = contract that defines what methods/properties a class must have
- Classes implement interfaces with :
- Multiple inheritance → implement many interfaces
- Default methods (C# 8+) → provide default behavior
- Polymorphism → treat different classes the same way via interface reference
- Interfaces are everywhere in real .NET: IEnumerable<T>, IDisposable, ILogger<T>, IRepository, etc.
Your Homework (Super Practical!)
- Create a new console project called InterfaceMaster
- Create these interfaces:
- IVehicle → Start(), Stop(), GetFuelLevel()
- IElectric → ChargeBattery()
- IGasoline → Refuel()
- Create classes:
- ElectricCar : IVehicle, IElectric
- GasCar : IVehicle, IGasoline
- HybridCar : IVehicle, IElectric, IGasoline
- In Program.cs: Create a list of IVehicle, loop through them, start each, and charge/refuel where possible
Next lesson: Generics – we’re going to learn how to write super reusable, type-safe code that works with any data type!
You’re doing absolutely fantastic! 🎉 Any part confusing? Want more examples with default methods or multiple interfaces? Just tell me — I’m right here for you! 💙
