interface (Riferimenti per C#)

Un'interfaccia definisce un contratto. Qualsiasi class, record o struct che implementa tale contratto deve fornire un'implementazione dei membri definiti nell'interfaccia . Un'interfaccia può definire un'implementazione predefinita per i membri. Può anche definire static membri per fornire una singola implementazione per le funzionalità comuni. A partire da C# 11, un'interfaccia può definire membri static abstract o static virtual per dichiarare che un tipo di implementazione deve fornire i membri dichiarati. In genere, i metodi static virtual dichiarano che un'implementazione deve definire un set di operatori di overload.

Nell'esempio seguente, la classe ImplementationClass deve implementare un metodo denominato SampleMethod che è privo di parametri e restituisce void.

Per altre informazioni e altri esempi, vedere Interfacce.

Interfaccia di esempio

interface ISampleInterface
{
    void SampleMethod();
}

class ImplementationClass : ISampleInterface
{
    // Explicit interface member implementation:
    void ISampleInterface.SampleMethod()
    {
        // Method implementation.
    }

    static void Main()
    {
        // Declare an interface instance.
        ISampleInterface obj = new ImplementationClass();

        // Call the member.
        obj.SampleMethod();
    }
}

Un'interfaccia può essere un membro di uno spazio dei nomi o di una classe. Una dichiarazione di interfaccia può contenere dichiarazioni (firme senza implementazione) dei membri seguenti:

Membri di interfaccia predefiniti

Queste dichiarazioni di membri precedenti in genere non contengono un corpo. Un membro dell'interfaccia può dichiarare un corpo. I corpi dei membri in un'interfaccia sono l'implementazione predefinita. I membri con corpi consentono all'interfaccia di fornire un'implementazione "predefinita" per classi e struct che non forniscono un'implementazione di override. Un'interfaccia può includere:

Membri astratti e virtuali statici

A partire da C# 11, un'interfaccia può dichiarare membri static abstract e static virtual per tutti i tipi di membri tranne i campi. Le interfacce possono dichiarare che l'implementazione dei tipi deve definire operatori o altri membri statici. Questa funzionalità consente agli algoritmi generici di specificare un comportamento simile al numero. È possibile visualizzare esempi nei tipi numerici nel runtime .NET, ad esempio System.Numerics.INumber<TSelf>. Queste interfacce definiscono operatori matematici comuni implementati da molti tipi numerici. Il compilatore deve risolvere le chiamate ai metodi static virtual e static abstract in fase di compilazione. I metodi static virtual e static abstract dichiarati nelle interfacce non hanno un meccanismo di invio di runtime analogo ai metodi virtual o abstract dichiarati nelle classi. Il compilatore usa invece le informazioni sul tipo disponibili in fase di compilazione. Pertanto, i metodi static virtual vengono dichiarati quasi esclusivamente nelle interfacce generiche. Inoltre, la maggior parte delle interfacce che dichiarano metodi static virtual o static abstract, dichiarano che uno dei parametri di tipo deve implementare l'interfaccia dichiarata. Ad esempio, l'interfaccia INumber<T> dichiara che T deve implementare INumber<T>. Il compilatore usa l'argomento tipo per risolvere le chiamate ai metodi e agli operatori dichiarati nella dichiarazione di interfaccia. Ad esempio, il tipo di int implementa INumber<int>. Quando il parametro di tipo T indica l'argomento di tipo int, vengono richiamati i membri static dichiarati in int. In alternativa, quando double è l'argomento di tipo, vengono richiamati i membri static dichiarati nel tipo double.

Importante

L’invio del metodo per i metodi static abstract e static virtual dichiarati nelle interfacce viene risolto usando il tipo di tempo di compilazione di un'espressione. Se il tipo di runtime di un'espressione è derivato da un tipo di tempo di compilazione diverso, verranno chiamati i metodi statici nel tipo di base (tempo di compilazione).

È possibile provare questa funzionalità usando l'esercitazione sui membri astratti statici nelle interfacce.

Ereditarietà dell'interfaccia

Le interfacce potrebbero non contenere lo stato dell'istanza. Mentre i campi statici sono ora consentiti, i campi dell'istanza non sono consentiti nelle interfacce. Le proprietà automatiche dell'istanza non sono supportate nelle interfacce, perché dichiarano in modo implicito un campo nascosto. Questa regola ha un effetto sottile sulle dichiarazioni di proprietà. In una dichiarazione di interfaccia, il codice seguente non dichiara una proprietà implementata automaticamente come avviene in un oggetto class o struct. Dichiara invece una proprietà che non ha un'implementazione predefinita, ma deve essere implementata in qualsiasi tipo che implementa l'interfaccia:

public interface INamed
{
  public string Name {get; set;}
}

Un'interfaccia può ereditare da una o più interfacce di base. Quando un'interfaccia esegue l'override di un metodo implementato in un'interfaccia di base, deve usare la sintassi esplicita di implementazione dell'interfaccia .

Quando un elenco di tipi di base contiene interfacce e una classe di base, la classe di base deve precedere le interfacce.

Una classe che implementa un'interfaccia può implementare in modo esplicito i membri di tale interfaccia. Non è possibile accedere a un membro implementato in modo esplicito tramite un'istanza di classe, ma solo tramite un'istanza dell'interfaccia. Inoltre, è possibile accedere ai membri di interfaccia predefiniti solo tramite un'istanza dell'interfaccia.

Per altre informazioni sull'implementazione esplicita dell'interfaccia, vedere Implementazione esplicita dell'interfaccia.

Implementazione dell'interfaccia di esempio

Nell'esempio seguente viene illustrata un'implementazione dell'interfaccia. In questo esempio l'interfaccia contiene la dichiarazione di proprietà e la classe contiene l'implementazione. Qualsiasi istanza di una classe che implementa IPoint presenta proprietà x e y di tipo Integer.

interface IPoint
{
    // Property signatures:
    int X { get; set; }

    int Y { get; set; }

    double Distance { get; }
}

class Point : IPoint
{
    // Constructor:
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    // Property implementation:
    public int X { get; set; }

    public int Y { get; set; }

    // Property implementation
    public double Distance =>
       Math.Sqrt(X * X + Y * Y);
}

class MainClass
{
    static void PrintPoint(IPoint p)
    {
        Console.WriteLine("x={0}, y={1}", p.X, p.Y);
    }

    static void Main()
    {
        IPoint p = new Point(2, 3);
        Console.Write("My Point: ");
        PrintPoint(p);
    }
}
// Output: My Point: x=2, y=3

Specifiche del linguaggio C#

Per altre informazioni, vedere la sezione interfacce della specifica del linguaggio C#, la specifica di funzionalità per C# 8 - Membri dell'interfaccia predefiniti, e la specifica di funzionalità per C# 11 - Membri astratti statici nelle interfacce

Vedi anche