Skip to main content

C# Interface Implementation

In this tutorial, we'll dive into how to implement interfaces in C#. Understanding interface implementation is crucial for writing clean, maintainable, and flexible code in object-oriented programming.

Introduction to Interface Implementation

An interface in C# defines a contract that classes must follow, but it doesn't provide any implementation details itself. When a class implements an interface, it must provide concrete implementations for all members defined in that interface. This creates a guaranteed set of functionalities that any implementing class will provide.

Basic Interface Implementation

Let's start with a simple example of how to implement an interface in C#:

csharp
// Define an interface
public interface ILogger
{
void LogMessage(string message);
void LogError(string error);
}

// Implement the interface in a class
public class FileLogger : ILogger
{
public void LogMessage(string message)
{
Console.WriteLine($"Log to file: {message}");
}

public void LogError(string error)
{
Console.WriteLine($"Error log to file: {error}");
}
}

In this example, FileLogger implements the ILogger interface. It must provide implementations for both LogMessage and LogError methods defined in the interface.

Implementing Multiple Interfaces

A class in C# can implement multiple interfaces simultaneously:

csharp
public interface IDataReader
{
string ReadData();
}

public interface IDataWriter
{
void WriteData(string data);
}

// Implementing multiple interfaces
public class FileHandler : IDataReader, IDataWriter
{
public string ReadData()
{
return "Data read from file";
}

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

The FileHandler class now must implement all methods from both IDataReader and IDataWriter interfaces.

Explicit Interface Implementation

Sometimes you might need to implement the same method name from different interfaces or want to hide interface implementations from the class's public API. C# allows explicit interface implementation for such scenarios:

csharp
public interface IDrawable
{
void Draw();
}

public interface IPrintable
{
void Draw(); // Same method name as in IDrawable
void Print();
}

// Using explicit implementation
public class Document : IDrawable, IPrintable
{
// Explicit implementation for IDrawable
void IDrawable.Draw()
{
Console.WriteLine("Drawing for display");
}

// Explicit implementation for IPrintable
void IPrintable.Draw()
{
Console.WriteLine("Drawing for printing");
}

public void Print()
{
Console.WriteLine("Printing document");
}
}

Usage example:

csharp
Document doc = new Document();
// doc.Draw(); // This won't compile because Draw is implemented explicitly

// To call the Draw methods:
((IDrawable)doc).Draw(); // Outputs: Drawing for display
((IPrintable)doc).Draw(); // Outputs: Drawing for printing

// Print is implemented implicitly, so it can be called directly
doc.Print(); // Outputs: Printing document

Interface Implementation with Properties

Interfaces can also define properties that implementing classes must provide:

csharp
public interface IVehicle
{
int Speed { get; set; }
string Model { get; }
void Start();
}

public class Car : IVehicle
{
public int Speed { get; set; } // Implemented property with getter and setter

public string Model { get; } // Implemented read-only property

public Car(string model)
{
Model = model;
}

public void Start()
{
Console.WriteLine($"The {Model} is starting. Current speed: {Speed}");
}
}

Example usage:

csharp
Car myCar = new Car("Tesla Model 3");
myCar.Speed = 60;
myCar.Start(); // Outputs: The Tesla Model 3 is starting. Current speed: 60

// Using the interface reference
IVehicle vehicle = myCar;
Console.WriteLine($"Vehicle model: {vehicle.Model}"); // Outputs: Vehicle model: Tesla Model 3

Default Interface Methods (C# 8.0+)

As of C# 8.0, interfaces can include default implementations for methods:

csharp
public interface INotification
{
void SendNotification(string message);

// Default implementation
void SendUrgentNotification(string message)
{
Console.WriteLine($"URGENT: {message}");
SendNotification(message);
}
}

public class EmailNotifier : INotification
{
public void SendNotification(string message)
{
Console.WriteLine($"Sending email: {message}");
}

// No need to implement SendUrgentNotification as it has a default implementation
}

Usage:

csharp
EmailNotifier emailService = new EmailNotifier();
emailService.SendNotification("Hello"); // Outputs: Sending email: Hello

// Using the default implementation
((INotification)emailService).SendUrgentNotification("System failure");
// Outputs:
// URGENT: System failure
// Sending email: System failure

Real-World Example: Dependency Injection

One practical application of interfaces is in dependency injection, which is widely used in modern software development for creating loosely coupled systems:

csharp
public interface IUserRepository
{
User GetById(int id);
List<User> GetAllUsers();
void Add(User user);
}

public class SqlUserRepository : IUserRepository
{
// SQL Server implementation
public User GetById(int id)
{
Console.WriteLine($"Getting user {id} from SQL database");
return new User { Id = id, Name = "John" };
}

public List<User> GetAllUsers()
{
Console.WriteLine("Getting all users from SQL database");
return new List<User>() { new User { Id = 1, Name = "John" } };
}

public void Add(User user)
{
Console.WriteLine($"Adding user {user.Name} to SQL database");
}
}

public class UserService
{
private readonly IUserRepository _userRepository;

// Constructor injection of the interface
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}

public User GetUser(int id)
{
return _userRepository.GetById(id);
}

public void RegisterUser(string name)
{
var user = new User { Name = name };
_userRepository.Add(user);
}
}

public class User
{
public int Id { get; set; }
public string Name { get; set; }
}

Usage example:

csharp
// In a real application, this would typically be done by a DI container
IUserRepository repository = new SqlUserRepository();
UserService service = new UserService(repository);

// Use the service
User user = service.GetUser(1);
Console.WriteLine($"Retrieved user: {user.Name}");

service.RegisterUser("Alice");

This pattern allows you to easily swap out implementations (e.g., replace SqlUserRepository with MongoUserRepository) without changing the UserService class.

Interface Implementation Best Practices

  1. Keep interfaces small and focused: Follow the Interface Segregation Principle (the "I" in SOLID) - many specific interfaces are better than one general-purpose interface.

  2. Name interfaces with the prefix 'I': This is a common convention in C# to clearly identify interfaces.

  3. Use interfaces for abstraction: Define interfaces for external dependencies and services to make testing and extending your code easier.

  4. Be consistent with implementation: Implement all members of an interface properly and ensure they work as expected.

  5. Consider explicit implementation when the interface method could conflict with other methods or should be hidden from the class's normal API.

Summary

Interface implementation is a powerful feature in C# that enables:

  • Creating contracts that classes must follow
  • Achieving polymorphism without inheritance
  • Building flexible, modular, and testable systems
  • Developing based on abstractions rather than concrete implementations

By understanding how to implement interfaces correctly, you'll be able to build more maintainable and flexible C# applications.

Exercises

  1. Create an interface IShape with methods CalculateArea() and CalculatePerimeter(). Implement this interface for at least three different shapes.

  2. Design a IPaymentProcessor interface and implement it for different payment methods (e.g., credit card, PayPal, crypto).

  3. Create a simple logging system with an ILogger interface and multiple implementations (console logger, file logger, database logger).

  4. Implement an interface that defines CRUD operations and create two different implementations for it (e.g., for SQL and for a web API).

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)