Menu
Coddy logo textTech

Explicit Interfaces

Part of the Object Oriented Programming section of Coddy's C# journey — lesson 28 of 70.

When a class implements multiple interfaces that have members with the same name, you face a naming collision. Explicit interface implementation solves this by letting you provide separate implementations for each interface.

With explicit implementation, you prefix the member name with the interface name and omit the access modifier:

public interface IAmericanPlug
{
    void Connect();
}

public interface IEuropeanPlug
{
    void Connect();
}

public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
    void IAmericanPlug.Connect()
    {
        Console.WriteLine("Connected to 120V");
    }
    
    void IEuropeanPlug.Connect()
    {
        Console.WriteLine("Connected to 220V");
    }
}

Explicitly implemented members can only be accessed through a variable of the interface type, not through the class itself:

var adapter = new UniversalAdapter();
// adapter.Connect();  // Won't compile!

IAmericanPlug american = adapter;
american.Connect();  // Connected to 120V

IEuropeanPlug european = adapter;
european.Connect();  // Connected to 220V

This technique is also useful when you want to hide interface members from the class's public API. If a method only makes sense when treating the object as a specific interface, explicit implementation keeps your class's surface area clean while still fulfilling the contract.

challenge icon

Challenge

Easy

Let's build a report generator system that demonstrates how explicit interface implementation lets a single class provide different behaviors depending on which interface is being used. You'll create a document that can be formatted differently for display versus printing.

You'll organize your code across four files:

  • IDisplayable.cs: Define an interface called IDisplayable in the Reports namespace. This interface represents content that can be shown on screen. It should declare a method Render() that returns a string.
  • IPrintable.cs: Define an interface called IPrintable in the Reports namespace. This interface represents content that can be sent to a printer. It should also declare a method Render() that returns a string - notice this creates a naming collision with IDisplayable!
  • Report.cs: Define a Report class in the Reports namespace that implements both IDisplayable and IPrintable. The report should have a Title property (string) and a Content property (string), with a constructor that sets both values. Use explicit interface implementation to provide different Render() behaviors:
    • When rendered for display: "[SCREEN] {Title}: {Content}"
    • When rendered for printing: "[PRINT] {Title} | {Content}"
  • Program.cs: In your main file, create a Report using input values. Since explicit implementations can only be accessed through interface variables, store the same report in both an IDisplayable variable and an IPrintable variable, then call Render() on each to show how the same object produces different output based on which interface you're using.

You will receive two inputs:

  • Report title
  • Report content

Print the output in this format:

Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}

For example, if the inputs are Sales Report and Q4 revenue increased by 15%, the output should be:

Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%

Notice how the same Report object behaves differently depending on which interface reference you use to access it. This is the power of explicit interface implementation - resolving naming collisions while providing context-appropriate behavior!

Cheat sheet

When a class implements multiple interfaces with members that have the same name, you can use explicit interface implementation to provide separate implementations for each interface.

To explicitly implement an interface member, prefix the member name with the interface name and omit the access modifier:

public interface IAmericanPlug
{
    void Connect();
}

public interface IEuropeanPlug
{
    void Connect();
}

public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
    void IAmericanPlug.Connect()
    {
        Console.WriteLine("Connected to 120V");
    }
    
    void IEuropeanPlug.Connect()
    {
        Console.WriteLine("Connected to 220V");
    }
}

Explicitly implemented members can only be accessed through a variable of the interface type, not through the class itself:

var adapter = new UniversalAdapter();
// adapter.Connect();  // Won't compile!

IAmericanPlug american = adapter;
american.Connect();  // Connected to 120V

IEuropeanPlug european = adapter;
european.Connect();  // Connected to 220V

This technique is useful for:

  • Resolving naming collisions between interface members
  • Hiding interface members from the class's public API when they only make sense in a specific interface context

Try it yourself

using System;
using Reports;

class Program
{
    public static void Main(string[] args)
    {
        // Read input
        string title = Console.ReadLine();
        string content = Console.ReadLine();

        // TODO: Create a Report object with the title and content

        // TODO: Store the report in an IDisplayable variable

        // TODO: Store the same report in an IPrintable variable

        // TODO: Print the display version by calling Render() on IDisplayable
        Console.WriteLine("Display version:");
        // Print the render result here

        // TODO: Print the print version by calling Render() on IPrintable
        Console.WriteLine("Print version:");
        // Print the render result here
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming