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:

csharp
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:

text
92
Bunga

Mari kita bedah baris demi baris:

  1. where T : IComparable<T>: Klausa constraint menuntut setiap type argument mengimplementasikan IComparable<T> untuk dirinya sendiri.
  2. a.CompareTo(b): Karena jaminan itu, compiler mengizinkan pemanggilan CompareTo; tanpa constraint, baris ini ditolak.
  3. return hasil >= 0 ? a : b;: Nilai CompareTo positif berarti a lebih besar; bila nol atau negatif, method mengembalikan b.
  4. NilaiTerbesar(87, 92): int mengimplementasikan IComparable<int>, sehingga pemanggilan ini sah.
  5. NilaiTerbesar("Bunga", "Budi"): string mengimplementasikan IComparable<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:

ConstraintJaminan pada T
where T : structT wajib value type non-nullable
where T : classT wajib reference type
where T : new()T wajib punya constructor publik tanpa parameter
where T : NamaKelasT wajib NamaKelas atau turunannya
where T : NamaInterfaceT wajib mengimplementasikan NamaInterface
where T : notnullT 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):

text
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.