Bab Generic Math memakai T.Zero dan T.One tanpa menjelaskan dari mana kemampuan itu berasal. Sumbernya adalah fitur bahasa bernama static abstract interface members: interface kini boleh mendeklarasikan anggota static sebagai kontrak, dan kode generik memanggil anggota tersebut lewat type parameter. Fitur ini membutuhkan .NET 7 dan C# 11, dan inilah pondasi yang membuat INumber<T> mungkin ada.
Mendeklarasikan Static Abstract Member #
Interface satuan berikut menjanjikan properti static Kode yang wajib diisi setiap implementator, serta method static virtual dengan implementasi bawaan:
public interface ISatuan<TSelf> where TSelf : ISatuan<TSelf>
{
static abstract string Kode { get; }
static virtual string Deskripsi()
{
return $"Satuan dengan kode {TSelf.Kode}";
}
}
public struct Meter : ISatuan<Meter>
{
public static string Kode => "m";
}
public struct Kilogram : ISatuan<Kilogram>
{
public static string Kode => "kg";
}Anggota static abstract tidak punya badan; setiap tipe implementator menyediakan isinya sendiri, mirip member abstract pada abstract class, tetapi untuk anggota static.
Memanggil Lewat Type Parameter #
Kode generik mengakses kedua anggota itu hanya melalui type parameter. Method pembantu berikut menjadi jembatan pemanggilan:
public static void TampilkanKode<T>() where T : ISatuan<T>
{
Console.WriteLine($"Kode satuan: {T.Kode}");
}
public static void TampilkanDeskripsi<T>() where T : ISatuan<T>
{
Console.WriteLine(T.Deskripsi());
}
Console.WriteLine(Meter.Kode);
TampilkanDeskripsi<Meter>();
TampilkanDeskripsi<Kilogram>();
TampilkanKode<Meter>();
TampilkanKode<Kilogram>();Output yang Dihasilkan:
m
Satuan dengan kode m
Satuan dengan kode kg
Kode satuan: m
Kode satuan: kgMari kita bedah baris demi baris:
static abstract string Kode { get; }: Kontrak properti static;MetermengisimdanKilogrammengisikg.static virtual string Deskripsi(): Anggota static virtual punya implementasi bawaan dan memanggilTSelf.Kodelewat type parameter milik interface.where TSelf : ISatuan<TSelf>: Constraint yang merujuk dirinya sendiri ini mengikat tipe implementator pada instantiasi interface yang tepat.Console.WriteLine(Meter.Kode): KarenaMetermenyediakan implementasiKode, akses langsung pada tipe konkret ini sah dan mencetakm.T.KodedanT.Deskripsi(): Di dalam kode generik, type parameterTadalah satu-satunya pintu ke anggota static interface.
Keterbatasan Akses #
Dua bentuk akses berikut ditolak compiler. Akses lewat nama interface langsung menghasilkan pesan berikut (pesan asli .NET SDK 9.0.319, path project dipangkas):
error CS8926: A static virtual or abstract interface member can be accessed only on a type parameter.Sementara itu, memanggil Deskripsi() seolah-olah anggota milik Kilogram juga ditolak, karena implementasi bawaan tetap menjadi milik interface:
error CS0117: 'Kilogram' does not contain a definition for 'Deskripsi'Kedua penolakan itu menegaskan pola pemakaian: anggota static interface dirancang untuk dipanggil dari kode generik lewat type parameter, bukan sebagai anggota bebas.
Dengan static abstract interface members, kontrak kini mencakup anggota static, dan kode generik memperoleh akses penuh ke konstanta maupun operator milik type parameter.