Gränssnitt – definiera beteende för flera typer

Ett gränssnitt innehåller definitioner för en grupp relaterade funktioner som en icke-abstrakt class eller en struct måste implementera. Ett gränssnitt kan definiera static metoder som måste ha en implementering. Ett gränssnitt kan definiera en standardimplementering för medlemmar. Ett gränssnitt får inte deklarera instansdata, till exempel fält, automatiskt implementerade egenskaper eller egenskapsliknande händelser.

Med hjälp av gränssnitt kan du till exempel inkludera beteende från flera källor i en klass. Den funktionen är viktig i C# eftersom språket inte stöder flera arv av klasser. Dessutom måste du använda ett gränssnitt om du vill simulera arv för structs, eftersom de faktiskt inte kan ärva från en annan struct eller klass.

Du definierar ett gränssnitt med nyckelordet interface som visas i följande exempel.

interface IEquatable<T>
{
    bool Equals(T obj);
}

Namnet på ett gränssnitt måste vara ett giltigt C#- identifierarnamn. Enligt konventionen börjar gränssnittsnamn med versaler I.

Alla klasser eller strukturer som implementerar IEquatable<T> gränssnittet måste innehålla en definition för en Equals metod som matchar den signatur som gränssnittet anger. Därför kan du räkna med att en klass som implementeras IEquatable<T> innehåller en Equals metod som en instans av klassen kan avgöra om den är lika med en annan instans av samma klass.

Definitionen av IEquatable<T> tillhandahåller inte någon implementering för Equals. En klass eller struct kan implementera flera gränssnitt, men en klass kan bara ärva från en enda klass.

Mer information om abstrakta klasser finns i Abstrakta och förseglade klasser och klassmedlemmar.

Gränssnitt kan innehålla instansmetoder, egenskaper, händelser, indexerare eller någon kombination av dessa fyra medlemstyper. Gränssnitt kan innehålla statiska konstruktorer, fält, konstanter eller operatorer. Från och med C# 11 kan gränssnittsmedlemmar som inte är fält vara static abstract. Ett gränssnitt får inte innehålla instansfält, instanskonstruktorer eller slutförare. Gränssnittsmedlemmar är offentliga som standard och du kan uttryckligen ange hjälpmedelsmodifierare, till exempel public, protected, internal, private, protected internaleller private protected. En private medlem måste ha en standardimplementering.

För att implementera en gränssnittsmedlem måste motsvarande medlem i implementeringsklassen vara offentlig, icke-statisk och ha samma namn och signatur som gränssnittsmedlemmen.

Kommentar

När ett gränssnitt deklarerar statiska medlemmar kan en typ som implementerar gränssnittet även deklarera statiska medlemmar med samma signatur. De är distinkta och unikt identifierade av den typ som deklarerar medlemmen. Den statiska medlem som deklareras i en typ åsidosätter inte den statiska medlem som deklarerats i gränssnittet.

En klass eller struct som implementerar ett gränssnitt måste tillhandahålla en implementering för alla deklarerade medlemmar utan en standardimplementering som tillhandahålls av gränssnittet. Men om en basklass implementerar ett gränssnitt ärver alla klasser som härleds från basklassen implementeringen.

I följande exempel visas en implementering av IEquatable<T> gränssnittet. Implementeringsklassen, Car, måste tillhandahålla en implementering av Equals metoden.

public class Car : IEquatable<Car>
{
    public string? Make { get; set; }
    public string? Model { get; set; }
    public string? Year { get; set; }

    // Implementation of IEquatable<T> interface
    public bool Equals(Car? car)
    {
        return (this.Make, this.Model, this.Year) ==
            (car?.Make, car?.Model, car?.Year);
    }
}

Egenskaper och indexerare för en klass kan definiera extra accessorer för en egenskap eller indexerare som definieras i ett gränssnitt. Ett gränssnitt kan till exempel deklarera en egenskap som har en get-accessor . Klassen som implementerar gränssnittet kan deklarera samma egenskap med både en get och ange-accessor . Men om egenskapen eller indexeraren använder explicit implementering måste åtkomsterna matcha. Mer information om explicit implementering finns i Explicit gränssnittsimplementering och gränssnittsegenskaper.

Gränssnitt kan ärva från ett eller flera gränssnitt. Det härledda gränssnittet ärver medlemmarna från dess basgränssnitt. En klass som implementerar ett härlett gränssnitt måste implementera alla medlemmar i det härledda gränssnittet, inklusive alla medlemmar i det härledda gränssnittets basgränssnitt. Klassen kan implicit konverteras till det härledda gränssnittet eller något av dess basgränssnitt. En klass kan innehålla ett gränssnitt flera gånger via basklasser som den ärver eller via gränssnitt som andra gränssnitt ärver. Klassen kan dock bara tillhandahålla en implementering av ett gränssnitt en gång och endast om klassen deklarerar gränssnittet som en del av definitionen av klassen (class ClassName : InterfaceName). Om gränssnittet ärvs på grund av att du ärvt en basklass som implementerar gränssnittet tillhandahåller basklassen implementeringen av medlemmarna i gränssnittet. Den härledda klassen kan dock omimplementering av virtuella gränssnittsmedlemmar i stället för att använda den ärvda implementeringen. När gränssnitt deklarerar en standardimplementering av en metod ärver alla klasser som implementerar gränssnittet den implementeringen (du måste skicka klassinstansen till gränssnittstypen för att få åtkomst till standardimplementeringen på gränssnittsmedlemmen).

En basklass kan också implementera gränssnittsmedlemmar med hjälp av virtuella medlemmar. I så fall kan en härledd klass ändra gränssnittets beteende genom att åsidosätta de virtuella medlemmarna. Mer information om virtuella medlemmar finns i Polymorfism.

Sammanfattning av gränssnitt

Ett gränssnitt har följande egenskaper:

  • I C#-versioner tidigare än 8.0 är ett gränssnitt som en abstrakt basklass med endast abstrakta medlemmar. En klass eller struct som implementerar gränssnittet måste implementera alla sina medlemmar.
  • Från och med C# 8.0 kan ett gränssnitt definiera standardimplementeringar för vissa eller alla medlemmar. En klass eller struct som implementerar gränssnittet behöver inte implementera medlemmar som har standardimplementeringar. Mer information finns i standardgränssnittsmetoder.
  • Ett gränssnitt kan inte instansieras direkt. Dess medlemmar implementeras av alla klasser eller strukturer som implementerar gränssnittet.
  • En klass eller struct kan implementera flera gränssnitt. En klass kan ärva en basklass och även implementera ett eller flera gränssnitt.