Bagikan melalui


Antarmuka - menentukan perilaku untuk beberapa jenis

Antarmuka berisi definisi untuk sekelompok fungsi terkait yang tidak abstrak class atau harus struct diterapkan. Antarmuka dapat menentukan static metode. Antarmuka dapat menentukan implementasi default untuk anggota. Antarmuka tidak dapat mendeklarasikan data instans seperti bidang, properti yang diimplementasikan secara otomatis, atau peristiwa seperti properti.

Dengan menggunakan antarmuka, Anda dapat, misalnya, menyertakan perilaku dari beberapa sumber di kelas. Kemampuan tersebut penting dalam C# karena bahasa tidak mendukung beberapa pewarisan kelas. Selain itu, Anda harus menggunakan antarmuka jika ingin menyimulasikan pewarisan untuk struktur, karena mereka tidak dapat benar-benar mewarisi dari struktur atau kelas lain.

Anda menentukan antarmuka dengan menggunakan interface kata kunci seperti yang ditunjukkan contoh berikut.

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

Nama antarmuka harus berupa nama pengidentifikasi C# yang valid. Menurut konvensi, nama antarmuka dimulai dengan modal I.

Setiap kelas atau struktur yang mengimplementasikan IEquatable<T> antarmuka harus berisi definisi untuk Equals metode yang cocok dengan tanda tangan yang ditentukan antarmuka. Akibatnya, Anda dapat mengandalkan kelas jenis T yang diimplementasikan untuk berisi IEquatable<T> metode yang instans Equals kelas ini dapat menentukan apakah itu sama dengan instans lain dari kelas yang sama.

Definisi IEquatable<T> tidak menyediakan implementasi untuk Equals. Kelas atau struktur dapat mengimplementasikan beberapa antarmuka, tetapi kelas hanya dapat mewarisi dari satu kelas.

Untuk informasi selengkapnya tentang kelas abstrak, lihat Kelas Abstrak dan Tersegel serta Anggota Kelas.

Antarmuka dapat berisi metode instans, properti, peristiwa, pengindeks, atau kombinasi apa pun dari empat jenis anggota tersebut. Antarmuka dapat berisi konstruktor statis, bidang, konstanta, atau operator. Anggota antarmuka yang bukan bidang bisa berupa static abstract. Antarmuka tidak dapat berisi bidang instans, konstruktor instans, atau finalizer. Anggota antarmuka bersifat publik secara default, dan Anda dapat secara eksplisit menentukan pengubah aksesibilitas, seperti public, , protected, internalprivate, protected internal, atau private protected. Anggota private harus memiliki implementasi default.

Untuk mengimplementasikan anggota antarmuka menggunakan implementasi implisit, anggota kelas pelaksana yang sesuai harus publik, non-statis, dan memiliki nama dan tanda tangan yang sama dengan anggota antarmuka. Anda harus menggunakan implementasi antarmuka eksplisit untuk menerapkan anggota antarmuka yang tidak dimaksudkan untuk menjadi publik.

Catatan

Ketika antarmuka mendeklarasikan anggota statis, jenis yang mengimplementasikan antarmuka tersebut mungkin juga mendeklarasikan anggota statis dengan tanda tangan yang sama. Anggota tersebut berbeda dan diidentifikasi secara unik oleh tipe yang mendeklarasikan anggota. Anggota statis yang dinyatakan dalam jenis tidak mengambil alih anggota statis yang dideklarasikan dalam antarmuka.

Kelas atau struktur yang mengimplementasikan antarmuka harus menyediakan implementasi untuk semua anggota yang dideklarasikan tanpa implementasi default yang disediakan oleh antarmuka. Namun, jika kelas dasar mengimplementasikan antarmuka, kelas apa pun yang berasal dari kelas dasar mewarisi implementasi tersebut.

Contoh berikut menunjukkan implementasi antarmuka IEquatable<T>. Kelas pelaksana, Car, harus menyediakan implementasi metode Equals.

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);
    }
}

Properti dan pengindeks kelas dapat menentukan aksesor tambahan untuk properti atau pengindeks yang dideklarasikan dalam antarmuka. Misalnya, antarmuka mungkin mendeklarasikan properti yang memiliki aksesor get. Kelas yang mengimplementasikan antarmuka dapat mendeklarasikan properti yang sama dengan get pengakses dan set. Namun, jika properti atau pengindeks menggunakan implementasi eksplisit, pengakses harus cocok. Untuk informasi selengkapnya tentang implementasi antarmuka eksplisit, lihat Implementasi Antarmuka Eksplisit dan Properti Antarmuka.

Antarmuka dapat mewarisi dari satu atau lebih antarmuka. Antarmuka turunan mewarisi anggota dari antarmuka dasarnya. Kelas yang mengimplementasikan antarmuka turunan harus mengimplementasikan semua anggota di antarmuka turunan, termasuk semua anggota antarmuka dasar antarmuka turunan. Kelas tersebut mungkin secara implisit dikonversi ke antarmuka turunan atau antarmuka dasarnya. Kelas mungkin mencakup antarmuka beberapa kali melalui kelas dasar yang diwarisi atau melalui antarmuka yang diwarisi antarmuka lain. Namun, kelas dapat menyediakan implementasi antarmuka hanya satu kali dan hanya jika kelas mendeklarasikan antarmuka sebagai bagian dari definisi kelas (class ClassName : InterfaceName). Jika antarmuka diwariskan karena Anda mewarisi kelas dasar yang mengimplementasikan antarmuka, kelas dasar menyediakan implementasi anggota antarmuka. Namun, kelas turunan dapat melengkapi kembali anggota antarmuka virtual apa pun alih-alih menggunakan implementasi yang diwariskan. Saat antarmuka mendeklarasikan implementasi default metode, kelas apa pun yang mengimplementasikan antarmuka tersebut mewarisi implementasi tersebut (Anda perlu mentransmisikan instans kelas ke jenis antarmuka untuk mengakses implementasi default pada anggota Antarmuka).

Kelas dasar juga dapat mengimplementasikan anggota antarmuka dengan menggunakan anggota virtual. Dalam hal ini, kelas turunan dapat mengubah perilaku antarmuka dengan mengambil alih anggota virtual. Untuk informasi selengkapnya mengenai anggota virtual, lihat Polymorphism.

Bekerja dengan antarmuka internal

Antarmuka internal biasanya dapat diimplementasikan menggunakan implementasi implisit dengan anggota publik, selama semua jenis dalam tanda tangan antarmuka dapat diakses secara publik. Namun, jika sebuah antarmuka menggunakan tipe internal dalam penandaan anggotanya, implementasi implisit menjadi tidak mungkin karena anggota kelas yang mengimplementasikannya harus bersifat terbuka saat mengekspos tipe internal. Dalam kasus seperti itu, Anda harus menggunakan implementasi antarmuka eksplisit.

Contoh berikut menunjukkan kedua skenario:

// Internal type that cannot be exposed publicly
internal class InternalConfiguration
{
    public string Setting { get; set; } = "";
}

// Internal interface that CAN be implemented with public members
// because it only uses public types in its signature
internal interface ILoggable
{
    void Log(string message); // string is public, so this works with implicit implementation
}

// Interface with internal accessibility using internal types
internal interface IConfigurable
{
    void Configure(InternalConfiguration config); // Internal type prevents implicit implementation
}

// This class shows both implicit and explicit interface implementation
public class ServiceImplementation : ILoggable, IConfigurable
{
    // Implicit implementation works for ILoggable because string is public
    public void Log(string message)
    {
        Console.WriteLine($"Log: {message}");
    }

    // Explicit implementation required for IConfigurable because it uses internal types
    void IConfigurable.Configure(InternalConfiguration config)
    {
        // Implementation here
        Console.WriteLine($"Configured with: {config.Setting}");
    }
    
    // If we tried implicit implementation for IConfigurable, this wouldn't compile:
    // public void Configure(InternalConfiguration config) // Error: cannot expose internal type
}

Dalam contoh sebelumnya, antarmuka IConfigurable menggunakan tipe internal InternalConfiguration dalam penandatanganan metode. Kelas ServiceImplementation tidak dapat menggunakan implementasi implisit karena itu akan memerlukan Configure metode menjadi publik, yang tidak diizinkan ketika deklarasi metode berisi tipe-tipe internal. Sebaliknya, implementasi antarmuka eksplisit digunakan, yang tidak memiliki pengubah akses dan hanya dapat diakses melalui jenis antarmuka.

Sebaliknya, ILoggable antarmuka dapat diimplementasikan secara implisit dengan anggota publik karena semua jenis dalam tanda tangannya (string) dapat diakses publik, meskipun antarmuka itu sendiri bersifat internal.

Untuk informasi selengkapnya tentang implementasi antarmuka eksplisit, lihat Implementasi Antarmuka Eksplisit.

Ringkasan antarmuka

Antarmuka memiliki properti berikut:

  • Dalam versi C# yang lebih lama dari 8.0, antarmuka seperti kelas dasar abstrak dengan hanya anggota abstrak. Kelas atau struktur yang mengimplementasikan antarmuka harus mengimplementasikan semua anggotanya.
  • Dimulai dengan C# 8.0, antarmuka dapat menentukan implementasi default untuk beberapa atau semua anggotanya. Kelas atau struktur yang mengimplementasikan antarmuka tidak harus mengimplementasikan anggota yang memiliki implementasi default. Untuk informasi selengkapnya, lihat metode antarmuka default.
  • Antarmuka tidak dapat diinstansiasi secara langsung.
  • Kelas atau struktur dapat mengimplementasikan satu atau beberapa antarmuka. Kelas dapat mewarisi kelas dasar dan juga mengimplementasikan satu atau beberapa antarmuka.