Menambahkan member baru pada interface yang sudah lama beredar memaksa setiap class implementasi menulis kode untuk member itu, termasuk class yang tidak membutuhkannya. Pada aplikasi loyalitas pelanggan, misalnya, kontrak IPelanggan ingin diperkaya method sapaan tanpa merusak ratusan class yang sudah mengimplementasikannya. Sejak C# 8, interface dapat membawa default implementation: member interface yang sudah berisi badan method. Class implementasi bebas memakai versi bawaan tersebut atau menggantinya dengan versi sendiri.
Deklarasi Default Member #
Default member ditulis seperti method biasa di dalam interface, lengkap dengan badan dan diakhiri titik koma di deklarasi property terpisah. Property yang dirujuk di dalam badan tetap harus dideklarasikan sebagai anggota kontrak, karena default implementation hanya berlaku untuk member yang punya badan. Fitur ini tersedia sejak C# 8.0, dan interface dengan default member kini mendekati kemampuan abstract class, yaitu menyimpan kode yang bisa dipakai langsung oleh implementasi.
Contoh: Sapaan Pelanggan #
public interface IPelanggan
{
string Nama { get; }
string Sapaan() => $"Halo, {Nama}!";
}
public class PelangganReguler : IPelanggan
{
public string Nama { get; }
public PelangganReguler(string nama)
{
Nama = nama;
}
}
public class PelangganVip : IPelanggan
{
public string Nama { get; }
public PelangganVip(string nama)
{
Nama = nama;
}
public string Sapaan()
{
return $"Selamat datang, {Nama}!";
}
}
IPelanggan reguler = new PelangganReguler("Sinta");
Console.WriteLine(reguler.Sapaan());
IPelanggan vip = new PelangganVip("Bunga");
Console.WriteLine(vip.Sapaan());Output yang Dihasilkan:
Halo, Sinta!
Selamat datang, Bunga!Mari kita bedah baris demi baris:
string Sapaan() => $"Halo, {Nama}!": Interface menyediakan badan bawaan yang memakai propertyNamamilik kontraknya sendiri; classPelangganRegulertidak menulis apa pun untuk method ini.class PelangganReguler : IPelanggan: Class ini hanya mengisi propertyNama; kompilasi tetap lulus karena methodSapaan()sudah terpenuhi oleh versi bawaan.public string Sapaan()padaPelangganVip: Class VIP memilih mengganti versi bawaan, dan implementasi class tersebut otomatis menang atas versi interface.reguler.Sapaan(): Pemanggilan melalui reference interface menjalankan versi bawaan karenaPelangganRegulertidak menyediakan pengganti, menghasilkan baris pertama output.vip.Sapaan(): Pemanggilan dengan bentuk sama menjalankan versiPelangganVip, membuktikan default member tetap mengikuti pola polymorphism.
Batasan Pemanggilan #
Default member hanya dapat dipanggil melalui variable yang bertipe interface-nya. Reference bertipe PelangganReguler tidak melihat method Sapaan(), karena member bawaan bukan bagian permukaan class; untuk memanggilnya, kita menampung object dalam variable IPelanggan terlebih dahulu. Batasan ini sejalan dengan explicit implementation pada bab sebelumnya: member milik interface hidup di dunia interface.
Dengan default implementation, interface kini mendukung evolusi bertahap. Bab berikutnya membahas covariance dan contravariance, aturan konversi antar tipe generic yang berhubungan melalui pewarisan.