Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Aanbeveling
Nieuw bij het ontwikkelen van software? Begin eerst met de handleiding Aan de slag. U krijgt interfaces te zien zodra u gedeeld gedrag moet definiëren voor niet-gerelateerde typen.
Ervaren in een andere taal? C#-interfaces zijn vergelijkbaar met interfaces in Java of protocollen in Swift. Skim de expliciete implementatiesectie voor C#-specifieke patronen.
Een interface definieert een contract: een groep gerelateerde methoden, eigenschappen, gebeurtenissen en indexeerfuncties die een class of struct meer moeten implementeren. Interfaces laten één type meerdere contracten implementeren, wat belangrijk is omdat C# geen ondersteuning biedt voor meerdere overname van klassen. Structs kunnen niet overnemen van andere structs of klassen, dus interfaces zijn de enige manier om gedeeld gedrag toe te voegen tussen structtypen.
In het volgende voorbeeld worden een interface en een klasse aangegeven waarmee deze wordt geïmplementeerd:
interface IEquatable<T>
{
bool Equals(T obj);
}
public class Car : IEquatable<Car>
{
public string? Make { get; set; }
public string? Model { get; set; }
public string? Year { get; set; }
public bool Equals(Car? car) =>
car is not null &&
(Make, Model, Year) == (car.Make, car.Model, car.Year);
}
Elke klasse of struct die IEquatable<T> implementeert, moet een Equals-methode bieden die overeenkomt met de interfacesignatuur. U kunt rekenen op elke IEquatable<T> implementatie ter ondersteuning van gelijkheidsvergelijking, ongeacht het concrete type. Die voorspelbaarheid is de kernwaarde van interfaces.
Een interface declareren
Definieer een interface met het interface trefwoord. Standaard beginnen interfacenamen met een hoofdletter I:
interface ILogger
{
void Log(string message);
string Name { get; }
}
Interfaces kunnen methoden, eigenschappen, gebeurtenissen en indexeerfuncties bevatten. Een interface kan geen exemplaarvelden, instantieconstructors of finalizers bevatten. Leden zijn standaard public. U kunt indien nodig andere toegankelijkheidsaanpassingen opgeven. Gebruik bijvoorbeeld internal voor leden die niet zichtbaar moeten zijn buiten de assembly.
Een interface implementeren
Een klasse of struct vermeldt de interfaces die worden geïmplementeerd na een dubbele punt in de declaratie. De klasse moet een implementatie bieden voor elk lid dat in de interface is gedeclareerd:
public class ConsoleLogger : ILogger
{
public string Name => "Console";
public void Log(string message) =>
Console.WriteLine($"[{Name}] {message}");
}
public class FileLogger : ILogger
{
public string Name => "File";
public void Log(string message)
{
// In a real app, write to a file
Console.WriteLine($"[{Name}] Writing to file: {message}");
}
}
Een klasse kan meerdere interfaces implementeren, gescheiden door komma's. Het moet implementaties bieden voor alle leden van elke interface die wordt vermeld.
Expliciete implementatie
Soms moet u een interfacelid implementeren zonder dat deze deel uitmaakt van de openbare API van de klasse. Expliciete implementatie kwalificeert het lid met de interface-naam. Het lid is alleen toegankelijk via een variabele van het interfacetype:
interface IMetric
{
double GetDistance(); // Returns meters
}
interface IImperial
{
double GetDistance(); // Returns feet
}
public class Runway(double meters) : IMetric, IImperial
{
// Explicit implementation for IMetric
double IMetric.GetDistance() => meters;
// Explicit implementation for IImperial
double IImperial.GetDistance() => meters * 3.28084;
}
Expliciete implementatie is handig wanneer twee interfaces leden met dezelfde naam declareren of wanneer u het openbare oppervlak van de klasse schoon wilt houden. Zie Expliciete interface-implementatie voor meer informatie.
Interface-erfelijkheid
Interfaces kunnen overnemen van een of meer andere interfaces. Een klasse die een afgeleide interface implementeert, moet alle leden van de afgeleide interface en alle bijbehorende basisinterfaces implementeren:
interface IDrawable
{
void Draw();
}
interface IShape : IDrawable
{
double Area { get; }
}
public class Circle(double radius) : IShape
{
public double Area => Math.PI * radius * radius;
public void Draw() =>
Console.WriteLine($"Drawing circle with area {Area:F2}");
}
Een klasse die IShape implementeert, kan impliciet worden geconverteerd naar IDrawable, omdat IShape daarvan erft.
Interfaces versus abstracte klassen
Zowel interfaces als abstracte klassen definiëren contracten waaraan afgeleide typen moeten voldoen.
- Gebruik een abstracte klasse wanneer gerelateerde typen de status (velden), constructors of niet-openbare leden delen. Met abstracte klassen kunt u een hiërarchie ontwikkelen door nieuwe leden toe te voegen met standaardgedrag zonder bestaande afgeleide typen te verbreken.
- Gebruik een interface wanneer een type moet voldoen aan een contract dat niet-gerelateerde hiërarchieën snijdt of wanneer het meerdere contracten moet implementeren. Interfaces kunnen geen instantievelden of constructors declareren, dus ze zijn het meest geschikt voor het toevoegen van mogelijkheden aan typen die al een basisklasse hebben. Voor geavanceerde scenario's bieden interfaces ook ondersteuning voor standaard implementaties van leden.
Een klasse kan slechts overnemen van één basisklasse, maar kan meerdere interfaces implementeren. Dit onderscheid maakt interfaces vaak de betere keuze voor het definiëren van mogelijkheden die zijn verdeeld over typehiërarchieën.
Werken met interne interfaces
U kunt doorgaans een interne interface met openbare leden implementeren, zolang alle typen in de interfacehandtekening openbaar toegankelijk zijn. Wanneer een interface gebruikmaakt van interne typen in de bijbehorende lidhandtekeningen, moet u expliciete implementatie gebruiken omdat het implementatielid niet openbaar kan zijn tijdens het weergeven van interne typen:
internal class InternalConfiguration
{
public string Setting { get; set; } = "";
}
internal interface ILoggable
{
void Log(string message);
}
internal interface IConfigurable
{
void Configure(InternalConfiguration config);
}
public class ServiceImplementation : ILoggable, IConfigurable
{
// Implicit implementation: ILoggable uses only public types in its signature
public void Log(string message) =>
Console.WriteLine($"Log: {message}");
// Explicit implementation: IConfigurable uses internal types
void IConfigurable.Configure(InternalConfiguration config) =>
Console.WriteLine($"Configured with: {config.Setting}");
}
In het voorgaande voorbeeld gebruikt IConfigurable een intern type InternalConfiguration in de methodehandtekening.
ServiceImplementation maakt gebruik van expliciete implementatie voor dat lid. Gebruikt daarentegen ILoggable alleen openbare typen (string) in de handtekening en kan impliciet worden geïmplementeerd.
Standaardinterfaceleden en statische abstracte leden
Interfaces ondersteunen twee geavanceerde functies die verder gaan dan basiscontracten:
- Standaardinterfaceleden laten een interface een hoofdtekst van een methode bieden. Implementatietypen nemen de standaard implementatie over en kunnen deze desgewenst overschrijven. Zie de standaardinterfacemethoden voor meer informatie.
- Statische abstracte leden vereisen implementatietypen om een statisch lid te bieden, wat handig is voor het definiëren van operatorcontracten of fabriekspatronen. Zie statische abstracte leden in interfaces voor meer informatie.
Beide functies worden behandeld in het artikel over interfaces in de taalreferentie. Het meeste dagelijkse interfacegebruik omvat het declareren en implementeren van patronen die eerder in dit artikel zijn beschreven.
Overzicht van interfaces
- Een interface definieert een contract met methoden, eigenschappen, gebeurtenissen en indexeerfuncties.
- Een klasse of struct die een interface implementeert, moet implementaties bieden voor alle gedeclareerde leden (tenzij de interface een standaard-implementatie biedt).
- U kunt een interface niet rechtstreeks instantiëren.
- Een klasse of struct kan meerdere interfaces implementeren. Een klasse kan een basisklasse overnemen en ook een of meer interfaces implementeren.
- Interfacenamen beginnen conventioneel met
I.