Back to Blog
C#

C# Multiple Interface Implementation: Syntax and Collisions

c# multiple interface implementation: Learn how to implement multiple interfaces in C#, handle name collisions, use explicit implementations, and design maintainable i...

C#Interfaces.NETExplicit Interface ImplementationType Design
Diagram showing a C# class node connected to multiple interface contracts, with a collision point resolved by an explicit implementation branch.

A C# class can implement any number of interfaces. The syntax is a comma-separated list after the class name, and the class must supply implementations for every abstract member declared in each interface. This is the foundation of c# multiple interface implementation, and it works the same way whether you implement two interfaces or ten.

The Core Syntax for Multiple Interfaces

Declaring a class that implements multiple interfaces is straightforward. List each interface after the colon, separated by commas.

public interface ILogger { void Log(string message); } public interface IAuditable { void RecordChange(string entity, string action); } public class OrderService : ILogger, IAuditable { public void Log(string message) { Console.WriteLine($"[LOG] {message}"); } public void RecordChange(string entity, string action) { Console.WriteLine($"[AUDIT] {entity}: {action}"); } }

The compiler verifies that every abstract member of ILogger and IAuditable has a matching implementation in OrderService. If any member is missing, compilation fails with a clear error. This is the simplest form of multiple interface implementation, and it covers most real-world cases.

When Two Interfaces Declare the Same Member

Name collisions happen when two interfaces declare members with the same signature. The class can provide a single public method that satisfies both interfaces.

public interface IWriter { void Write(string content); } public interface IPersister { void Write(string content); } public class FileHandler : IWriter, IPersister { public void Write(string content) { File.WriteAllText("output.txt", content); } }

One Write method now fulfills both IWriter.Write and IPersister.Write. This is acceptable when the two interfaces mean the same thing. But when the interfaces expect different behavior for an identical signature, a single implementation is wrong. For example, IWriter.Write might mean "render to the display" while IPersister.Write means "append to storage." One method cannot honestly do both.

Explicit Interface Implementation for Colliding Members

Explicit interface implementation gives each interface its own implementation, even when the signatures match.

public class DualWriter : IWriter, IPersister { void IWriter.Write(string content) { Console.WriteLine($"Display: {content}"); } void IPersister.Write(string content) { File.AppendAllText("persisted.txt", content); } }

Each member is prefixed with the interface name, and the member is only accessible through a reference of that interface type. This code does not compile:

var writer = new DualWriter(); writer.Write("hello"); // CS1061: DualWriter does not contain a definition for Write

You must cast first:

IWriter writer = new DualWriter(); writer.Write("hello"); // calls the display implementation IPersister persister = new DualWriter(); persister.Write("hello"); // calls the file implementation

The tradeoff is intentional: you get separate behavior per interface, but the members are hidden from the class's public surface. Use explicit implementation when the interface member is not a natural part of the class's own API.

Default Interface Methods and Multiple Implementation

C# 8 added default interface methods, which let an interface provide a body for a member. A class is not required to override a default member. The interaction with multiple interfaces has a specific rule: when two interfaces each provide a default implementation for the same signature, the implementing class must resolve the ambiguity.

public interface ILogger { void Log(string message) => Console.WriteLine($"Default log: {message}"); } public interface IAuditable { void Log(string message) => Console.WriteLine($"Default audit: {message}"); } public class Service : ILogger, IAuditable { public void Log(string message) { Console.WriteLine($"Service: {message}"); } }

If Service omits its own Log, the compiler reports an ambiguity error because neither default implementation takes precedence. The class must provide an override that decides what the combined behavior should be. This rule prevents the runtime from silently choosing one interface's default over another.

Casting and Runtime Type Behavior

A class that implements multiple interfaces can be used as any of those interface types. The runtime type stays the same; the interface reference only restricts which members are visible.

object obj = new OrderService(); if (obj is ILogger logger) { logger.Log("Pattern matching works"); } IAuditable auditable = (IAuditable)obj; auditable.RecordChange("Order", "Created");

This matters when you pass objects to methods that accept a specific interface. The method sees only that interface's contract, even though the underlying object implements more. is and as checks behave normally, and pattern matching with interface types works as expected. There is no performance penalty beyond the standard interface dispatch cost, which the JIT handles efficiently for sealed and well-typed call sites.

Design Considerations and Maintainability

Implementing many interfaces on one class increases coupling. Each interface is a contract, and the class must track changes to every contract it promises. A class that implements five interfaces changes more often than one that implements two.

Interface segregation is the main tool here. Prefer small, focused interfaces over a single large one. A class that implements ILogger, IAuditable, and IPersister separately is easier to test and swap than one that implements a combined IService interface bundling all three concerns.

Explicit implementation also affects maintainability. It keeps interface-specific members out of the class's public surface, which is useful when the member is only meaningful in the context of that interface. But it forces callers to cast, so it adds friction at call sites. Reserve it for genuine collisions or for members that should not be part of the class's public API.

The decision between a single shared implementation and explicit per-interface implementations comes down to semantics. If the interfaces mean the same thing, share one method. If they mean different things, split them explicitly. That rule keeps the code honest and prevents subtle bugs where one interface's callers receive behavior meant for another.

c# multiple interface implementation: Practical Usage and Co | RYUSLOG DEV