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.
Un'interfaccia di primo livello, una dichiarata in uno spazio dei nomi ma non annidata all'interno di un altro tipo, può essere dichiarata public
o internal
. Il valore predefinito è internal
. Le dichiarazioni di interfaccia annidate, dichiarate all'interno di un altro tipo, possono essere dichiarate usando qualsiasi modificatore di accesso.
I membri dell'interfaccia senza un'implementazione non possono includere un modificatore di accesso. I membri con un'implementazione predefinita possono includere qualsiasi modificatore di accesso.
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.
Importante
L'aggiunta di membri di interfacce predefinite forza qualsiasi ref struct
che implementa l'interfaccia ad aggiungere una dichiarazione esplicita di tale membro.
Un'interfaccia può includere:
- Costanti
- Operatori
- Costruttore statico.
- Tipi annidati
- Campi statici, metodi, proprietà, indicizzatori ed eventi
- Dichiarazioni membro che usano la sintassi esplicita di implementazione dell'interfaccia.
- Modificatori di accesso espliciti (l'accesso predefinito è
public
).
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 class
oggetto 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 eredita da un'altra interfaccia, un tipo che implementa l'interfaccia derivata deve implementare tutti i membri nelle interfacce di base e quelli dichiarati nell'interfaccia derivata, come illustrato nel codice seguente:
public interface I1
{
void M1();
}
public interface I2 : I1
{
void M2();
}
public class C : I2
{
// implements I1.M1
public void M1() { }
// implements I2.M2
public void M2() { }
}
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