English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Interfaccia di C# (Interface)

Nel mondo umano, i vincoli di contratto tra due o più persone li costringono a comportarsi secondo il contratto. Allo stesso modo, un'interfaccia include dichiarazioni di funzionalità correlate. L'entità che implementa l'interfaccia deve fornire l'implementazione delle funzionalità dichiarate.

In C#, è possibile definire un'interfaccia utilizzando la parola chiave interface. Un'interfaccia può contenere dichiarazioni di metodi, proprietà, indici e eventi. Tuttavia, non può contenere campi, proprietà implementate automaticamente.

Di seguito viene dichiarato un'interfaccia che definisce alcune funzionalità di base per le operazioni di file.

interface IFile
{
    void ReadFile();
    void WriteFile(string text);
}

Non è possibile applicare modificatori di accesso ai membri dell'interfaccia. Di default, tutti i membri sono pubblici. Se si utilizzano modificatori di accesso nell'interfaccia, il compilatore C# fornirà un errore durante la compilazione: “Il modificatore 'public/private/protected' non è valido per questo elemento.” (Visual Studio mostrerà immediatamente l'errore senza procedere con la compilazione).

interface IFile
{
    protected void ReadFile(); // Errore durante la compilazione
    private void WriteFile(string text); // Errore durante la compilazione
}

Le interfacce possono contenere solo dichiarazioni e non implementazioni. Di seguito verrà fornito un errore durante la compilazione.

interface IFile
{
    void ReadFile();
    void WriteFile(string text){
        Console.Write(text); // Errore: impossibile implementare il metodo
    }
}

Implementazione dell'interfaccia

Un oggetto classe o un oggetto Struct può implementare un o più interfacce utilizzando due punti ( : ).  

Sintassi:

<NomeClasseOgggetto> : <NomeInterfaccia>

Ad esempio, il seguente oggetto classe implementa implicitamente l'interfaccia IFile.

interface IFile
{
    void ReadFile();
    void WriteFile(string text);
}
class FileInfo : IFile
{
    public void ReadFile()
    {
        Console.WriteLine("Lettura del file");
    }
    public void WriteFile(string text)
    {
        Console.WriteLine("Scrittura nel file");
    }
}

Nell'esempio sopra, la classe FileInfo ha implementato l'interfaccia IFile. Utilizza l'accessore public per definire tutti i membri dell'interfaccia IFile. La classe FileInfo può anche includere altri membri oltre ai membri dell'interfaccia.

I membri dell'interfaccia devono essere implementati con il modificatore public; altrimenti, il compilatore genererà un errore durante la compilazione.

Puoi creare un oggetto della classe e assegnarlo a una variabile di tipo interfaccia, come indicato di seguito.

public class Program
{
    public static void Main()
    {
        IFile file1 = new FileInfo();
        FileInfo file2 = new FileInfo();
        file1.ReadFile(); 
        file1.WriteFile("content"); 
        file2.ReadFile(); 
        file2.WriteFile("content"); 
    }
}

Sopra, abbiamo creato un oggetto della classe FileInfo e lo abbiamo assegnato a una variabile di tipo IFile e a una variabile di tipo FileInfo. Quando si implementa implicitamente l'interfaccia, è possibile accedere ai membri IFile utilizzando la variabile di tipo IFile e la variabile di tipo FileInfo.

Implementazione esplicita

Un'interfaccia può essere implementata esplicitamente utilizzando <InterfaceName>.<MemberName>. Quando una classe sta implementando più interfacce, l'implementazione esplicita è utile; di conseguenza, è più facile da leggere e elimina la confusione. È utile anche quando le interfacce hanno lo stesso nome del metodo.

Non mescolare public I modificatori possono essere usati insieme all'implementazione esplicita. Questo genererà un errore durante la compilazione.
interface IFile
{
    void ReadFile();
    void WriteFile(string text);
}
    
class FileInfo : IFile
{
    void IFile.ReadFile()
    {
        Console.WriteLine("Lettura del file");
    }
    void IFile.WriteFile(string text)
    {
        Console.WriteLine("Scrittura nel file");
    }
}

Quando si implementa un'interfaccia esplicitamente, i membri dell'interfaccia possono essere acceduti solo attraverso l'istanza del tipo dell'interfaccia.

interface IFile
{
    void ReadFile();
    void WriteFile(string text);
}
class FileInfo : IFile
{
    void IFile.ReadFile()
    {
        Console.WriteLine("Lettura del file");
    }
    void IFile.WriteFile(string text)
    {
        Console.WriteLine("Scrittura nel file");
    }
    public void Search(string text)
    {
        Console.WriteLine("Ricerca nel file");
    }
}
public class Program
{
    public static void Main()
    {
        IFile file1 = new FileInfo();
        FileInfo file2 = new FileInfo();
        file1.ReadFile(); 
        file1.WriteFile("content"); 
        //file1.Search("text to be searched")//errore durante la compilazione 
        
        file2.Search("text to be searched");
        //file2.ReadFile(); //errore durante la compilazione 
        //file2.WriteFile("content"); //errore durante la compilazione 
    }
}

Nell'esempio sopra, l'oggetto file1 può accedere solo ai membri IFile, mentre file2 può accedere ai membri della classe FileInfo. Questa è la limitazione dell'implementazione esplicita.

Implementazione di più interfacce

Un'istanza di classe o struttura può implementare più interfacce. Deve fornire l'implementazione di tutti i membri di tutte le interfacce.

interface IFile
{
    void ReadFile();
}
interface IBinaryFile
{
    void OpenBinaryFile();
    void ReadFile();
}
class FileInfo : IFile, IBinaryFile
{
    void IFile.ReadFile()
    {
        Console.WriteLine("Lettura del File Testuale");
    }
    void IBinaryFile.OpenBinaryFile()
    {
        Console.WriteLine("Apertura del File Binario");
    }
    void IBinaryFile.ReadFile()
    {
        Console.WriteLine("Lettura del File Binario");
    }
    public void Search(string text)
    {
        Console.WriteLine("Ricerca nel File");
    }
}
public class Program
{
    public static void Main()
    {
        IFile file1 = new FileInfo();
        IBinaryFile file2 = new FileInfo();
        FileInfo file3 = new FileInfo();
        file1.ReadFile(); 
        //file1.OpenBinaryFile(); //Errore di compilazione 
        //file1.SearchFile("text to be searched"); //Errore di compilazione 
        
        file2.OpenBinaryFile();
        file2.ReadFile();
        //file2.SearchFile("text to be searched"); //Errore di compilazione 
    
        file3.Search("text to be searched");
        //file3.ReadFile(); //Errore di compilazione 
        //file3.OpenBinaryFile(); //Errore di compilazione 
    }
}

Sopra, FileInfo ha implementato due interfacce, IFile e IBinaryFile esplicitamente implementate. Si consiglia di implementare esplicitamente le interfacce quando si implementano più interfacce, per evitare confusione e migliorare la leggibilità.

Punti da ricordare:
  1. Un'interfaccia può contenere dichiarazioni di metodo, proprietà, indici e eventi.

  2. Un'interfaccia non può contenere membri privati, protetti o interni. Di default, tutti i membri sono pubblici.

  3. Un'interfaccia non può contenere campi e attributi implementati automaticamente.

  4. Una classe o una struttura può implementare implicitamente o esplicitamente una o più interfacce. Utilizzare il modificatore public per implementare implicitamente l'interfaccia, e non utilizzarlo nel caso di implementazione esplicita.

  5. Implementare esplicitamente l'interfaccia utilizzando InterfaceName. MemberName.

  6. Un'interfaccia può ereditare una o più interfacce.