Interface Implementation

Vaibhav • September 10, 2025

In the previous article, we explored the fundamentals of interfaces - how they define contracts without implementation and enable polymorphism across unrelated types. Now it’s time to put those ideas into practice. In this article, we’ll walk through how to implement interfaces in C#, how to handle multiple interfaces, how to resolve naming conflicts, and how to design clean, maintainable interface-based code. We’ll build on everything you’ve learned so far about classes, methods, and polymorphism.

Implementing a single interface

To implement an interface, a class must provide concrete definitions for all the members declared in the interface. This is a strict requirement - if any member is missing, the compiler will raise an error. Let’s start with a simple example.

interface IGreeter
{
    void Greet(string name);
}

class ConsoleGreeter : IGreeter
{
    public void Greet(string name)
    {
        Console.WriteLine($"Hello, {name}!");
    }
}

The ConsoleGreeter class implements IGreeter by providing a definition for Greet(). You can now use this class wherever an IGreeter is expected.

IGreeter greeter = new ConsoleGreeter();
greeter.Greet("Vaibhav");

This code demonstrates interface-based polymorphism. The variable greeter is typed as IGreeter, but it holds a ConsoleGreeter instance. The method call is resolved at runtime.

Interfaces can be used as method parameters, return types, and collection types - anywhere you want to abstract away the concrete implementation.

Implementing multiple interfaces

C# allows a class to implement multiple interfaces. This is one of the key advantages of interfaces over classes, which only support single inheritance. Let’s look at an example.

interface IReader
{
    void Read();
}

interface IWriter
{
    void Write(string content);
}

class FileHandler : IReader, IWriter
{
    public void Read()
    {
        Console.WriteLine("Reading from file...");
    }

    public void Write(string content)
    {
        Console.WriteLine($"Writing to file: {content}");
    }
}

The FileHandler class implements both IReader and IWriter. This allows it to be used in contexts that require reading, writing, or both.

IReader reader = new FileHandler();
reader.Read();

IWriter writer = new FileHandler();
writer.Write("Hello world");

This flexibility is especially useful in layered architectures, where different components interact through interfaces without knowing the underlying implementation.

Resolving method name conflicts

If two interfaces define methods with the same signature, and a class implements both, you may run into naming conflicts. C# provides a way to resolve this using explicit interface implementation.

interface IPrinter
{
    void Print();
}

interface IScanner
{
    void Print();
}

class MultiFunctionDevice : IPrinter, IScanner
{
    void IPrinter.Print()
    {
        Console.WriteLine("Printing document...");
    }

    void IScanner.Print()
    {
        Console.WriteLine("Scanning document...");
    }
}

In this example, MultiFunctionDevice implements both IPrinter and IScanner, each with a Print() method. By using explicit implementation, the class avoids ambiguity and keeps the methods separate.

MultiFunctionDevice device = new MultiFunctionDevice();

((IPrinter)device).Print(); // Prints
((IScanner)device).Print(); // Scans

You must cast the object to the appropriate interface to access the correct method. This technique is useful when you want to hide interface methods from the public API of the class.

Explicit interface methods are not accessible via the class instance directly. They are only available through the interface reference.

Interface implementation and access modifiers

Interface members are always public by definition. When implementing an interface, the corresponding methods in the class must also be public - otherwise, the compiler will complain.

interface ICalculator
{
    int Add(int a, int b);
}

class SimpleCalculator : ICalculator
{
    // Must be public
    public int Add(int a, int b)
    {
        return a + b;
    }
}

If you try to make Add() private or protected, the compiler will raise an error. This ensures that interface contracts are always accessible to consumers.

Interface implementation and inheritance

A class that inherits from a base class can also implement interfaces. This allows you to combine inheritance and interface-based design. Let’s look at an example.

class BaseLogger
{
    public void Log(string message)
    {
        Console.WriteLine($"Base log: {message}");
    }
}

interface INotifier
{
    void Notify(string message);
}

class EmailLogger : BaseLogger, INotifier
{
    public void Notify(string message)
    {
        Console.WriteLine($"Sending email: {message}");
    }
}

The EmailLogger class inherits logging behavior from BaseLogger and adds notification capability via INotifier. This pattern is common in real-world systems where classes need both shared behavior and flexible contracts.

Interface implementation and testing

Interfaces make unit testing easier. You can create mock implementations of interfaces to simulate behavior without relying on real dependencies. This allows you to isolate logic and verify interactions.

interface ILogger
{
    void Log(string message);
}

class MockLogger : ILogger
{
    public List Messages = new List();

    public void Log(string message)
    {
        Messages.Add(message);
    }
}

You can inject MockLogger into your code and verify that logging occurred, without printing to the console or writing to a file. This technique is widely used in test-driven development.

Interface implementation and dependency injection

Interfaces are central to dependency injection - a design pattern that promotes loose coupling. Instead of hardcoding dependencies, you depend on interfaces and inject concrete implementations at runtime.

interface IDataStore
{
    void Save(string data);
}

class FileStore : IDataStore
{
    public void Save(string data)
    {
        Console.WriteLine($"Saving to file: {data}");
    }
}

class Processor
{
    private readonly IDataStore _store;

    public Processor(IDataStore store)
    {
        _store = store;
    }

    public void Run()
    {
        _store.Save("Important data");
    }
}

The Processor class depends on IDataStore, not FileStore. This allows you to swap in different implementations (e.g., DatabaseStore, CloudStore) without changing the Processor code.

Always depend on interfaces, not concrete classes. This makes your code more flexible, testable, and maintainable.

Interface implementation and design principles

Implementing interfaces supports several key design principles:

The Interface Segregation Principle encourages you to keep interfaces small and focused. Instead of one large interface with many methods, define multiple smaller interfaces that reflect distinct capabilities. This makes implementation easier and avoids forcing classes to implement methods they don’t need.

interface IReadable
{
    void Read();
}

interface IWritable
{
    void Write(string content);
}

A class can implement only the interfaces it needs. This leads to cleaner, more maintainable code.

Summary

Interface implementation is a core skill in C# development. It allows you to define contracts, support polymorphism, and build flexible, testable systems. You’ve learned how to implement single and multiple interfaces, resolve naming conflicts, use explicit implementation, and combine interfaces with inheritance. You’ve also seen how interfaces support testing, dependency injection, and clean design principles. By mastering interface implementation, you’ll be able to write code that’s modular, extensible, and easy to reason about.

In the next article, we’ll explore Casting and Type Checking - how to safely convert between types and verify object compatibility at runtime.