Menu
Coddy logo textTech

Interfacce esplicite

Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 28 di 70.

Quando una classe implementa più interfacce che hanno membri con lo stesso nome, si verifica una collisione di nomi. L'implementazione esplicita delle interfacce risolve il problema consentendoti di fornire implementazioni separate per ciascuna interfaccia.

Con un'implementazione esplicita, anteponi il nome dell'interfaccia al nome del membro e ometti il modificatore di accesso:

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");
    }
}

I membri implementati esplicitamente sono accessibili solo tramite una variabile del tipo dell’interfaccia, non tramite la classe stessa:

var adapter = new UniversalAdapter();
// adapter.Connect();  // Non compila!

IAmericanPlug american = adapter;
american.Connect();  // Collegato a 120V

IEuropeanPlug european = adapter;
european.Connect();  // Collegato a 220V

Questa tecnica è utile anche quando vuoi nascondere i membri dell'interfaccia dall'API pubblica della classe. Se un metodo ha senso solo quando si considera l'oggetto come un'interfaccia specifica, l'implementazione esplicita mantiene pulita la superficie della tua classe, pur rispettando il contratto.

challenge icon

Sfida

Facile

Costruiamo un sistema di generazione di report che mostri come l'implementazione esplicita di un'interfaccia consenta a una singola classe di fornire comportamenti diversi a seconda dell'interfaccia utilizzata. Creerai un documento che può essere formattato in modo diverso per la visualizzazione e per la stampa.

Organizzerai il codice in quattro file:

  • IDisplayable.cs: Definisci un'interfaccia chiamata IDisplayable nello spazio dei nomi Reports. Questa interfaccia rappresenta contenuti che possono essere visualizzati sullo schermo. Deve dichiarare un metodo Render() che restituisce una stringa.
  • IPrintable.cs: Definisci un'interfaccia chiamata IPrintable nello spazio dei nomi Reports. Questa interfaccia rappresenta contenuti che possono essere inviati a una stampante. Deve dichiarare anche un metodo Render() che restituisce una stringa: nota che questo crea una collisione di nomi con IDisplayable!
  • Report.cs: Definisci una classe Report nello spazio dei nomi Reports che implementa sia IDisplayable sia IPrintable. Il report deve avere una proprietà Title (string) e una proprietà Content (string), con un costruttore che imposta entrambi i valori. Usa l'implementazione esplicita dell'interfaccia per fornire comportamenti diversi per Render():
    • Quando viene visualizzato: "[SCREEN] {Title}: {Content}"
    • Quando viene stampato: "[PRINT] {Title} | {Content}"
  • Program.cs: Nel file principale, crea un Report usando i valori di input. Poiché è possibile accedere alle implementazioni esplicite solo tramite variabili di interfaccia, assegna lo stesso report sia a una variabile IDisplayable sia a una variabile IPrintable, poi chiama Render() su ciascuna per mostrare come lo stesso oggetto produca output diversi a seconda dell'interfaccia usata.

Riceverai due input:

  • Titolo del report
  • Contenuto del report

Stampa l'output in questo formato:

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

Per esempio, se gli input sono Sales Report e Q4 revenue increased by 15%, l'output dovrebbe essere:

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

Nota come lo stesso oggetto Report si comporti diversamente a seconda del riferimento all'interfaccia usato per accedervi. Questo è il potere dell'implementazione esplicita delle interfacce: risolvere le collisioni di nomi fornendo al contempo un comportamento appropriato al contesto!

Provalo tu

using System;
using Reports;

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

        // TODO: Crea un oggetto Report con il titolo e il contenuto

        // TODO: Memorizza il report in una variabile IDisplayable

        // TODO: Memorizza lo stesso report in una variabile IPrintable

        // TODO: Stampa la versione per la visualizzazione chiamando Render() su IDisplayable
        Console.WriteLine("Display version:");
        // Stampa qui il risultato del rendering

        // TODO: Stampa la versione per la stampa chiamando Render() su IPrintable
        Console.WriteLine("Print version:");
        // Stampa qui il risultato del rendering
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C# online