Sebuah method generik harus bisa dikompilasi untuk semua tipe yang mungkin dipakai pemanggil, dan di situlah masalahnya: tanpa informasi tambahan, compiler tidak menjamin T punya anggota apa pun selain anggota object. Kita tidak dapat memanggil a.CompareTo(b) pada T sembarangan karena tidak semua tipe bisa dibandingkan. Generic constraints menjawab masalah ini lewat klausa where, yang menjanjikan kemampuan minimum setiap type argument.
Constraint IComparable<T> #
Method pencari nilai terbesar membutuhkan jaminan bahwa T dapat membandingkan dirinya dengan sesama T. Interface IComparable<T> menyatakan jaminan itu:
public static T NilaiTerbesar<T>(T a, T b) where T : IComparable<T>
{
int hasil = a.CompareTo(b);
return hasil >= 0 ? a : b;
}
Console.WriteLine(NilaiTerbesar(87, 92));
Console.WriteLine(NilaiTerbesar("Bunga", "Budi"));Output yang Dihasilkan:
92
BungaMari kita bedah baris demi baris:
where T : IComparable<T>: Klausa constraint menuntut setiap type argument mengimplementasikanIComparable<T>untuk dirinya sendiri.a.CompareTo(b): Karena jaminan itu, compiler mengizinkan pemanggilanCompareTo; tanpa constraint, baris ini ditolak.return hasil >= 0 ? a : b;: NilaiCompareTopositif berartialebih besar; bila nol atau negatif, method mengembalikanb.NilaiTerbesar(87, 92):intmengimplementasikanIComparable<int>, sehingga pemanggilan ini sah.NilaiTerbesar("Bunga", "Budi"):stringmengimplementasikanIComparable<string>; perbandingan karakter per karakter menempatkan “Bunga” setelah “Budi”.
Ragam Constraint #
Klausa where mendukung beberapa jenis batasan, dan kita boleh menggabungkan beberapa constraint dalam satu deklarasi dengan koma:
| Constraint | Jaminan pada T |
|---|---|
where T : struct | T wajib value type non-nullable |
where T : class | T wajib reference type |
where T : new() | T wajib punya constructor publik tanpa parameter |
where T : NamaKelas | T wajib NamaKelas atau turunannya |
where T : NamaInterface | T wajib mengimplementasikan NamaInterface |
where T : notnull | T wajib bukan null |
where T : struct, IComparable<T> | Gabungan beberapa jaminan sekaligus |
Pesan Galat Bila Constraint Dilanggar #
Class Buku pada bab Generic Class tidak mengimplementasikan IComparable<Buku>. Bila kita memanggil NilaiTerbesar(new Buku(), new Buku()), compiler menolak program tersebut dengan pesan berikut (pesan asli .NET SDK 9.0.319, path project dipangkas):
error CS0311: The type 'Buku' cannot be used as type parameter 'T' in the generic type or method 'Program.NilaiTerbesar<T>(T, T)'. There is no implicit reference conversion from 'Buku' to 'System.IComparable<Buku>'.Pesan tersebut menegaskan letak masalahnya: tidak ada konversi dari Buku ke System.IComparable<Buku>. Penolakan terjadi pada saat kompilasi, bukan menunggu galat runtime.
Constraint membuat kode generik tetap umum, tetapi tetap boleh mengandalkan kemampuan yang dijanjikan type argument.