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.