Karena string mewarisi object, wajar kita berharap string[] dapat dipandang sebagai object[]. Harapan itu benar dan disebut covariance: konversi mengikuti arah pewarisan tipe. Arah sebaliknya juga punya nama, contravariance, dan berguna untuk parameter method. Bab ini membahas variance pada array dan pengantar variance pada tipe generic IEnumerable<T>, Func<T>, dan Action<T>; pembahasan mendalam tersedia pada section Generics.
Covariance pada Array #
Array di C# bersifat covariant terhadap tipe elemennya, sehingga penugasan object[] kotak = daftarString sah menurut compiler. Namun, array menyimpan elemen dan menerima penulisan, sehingga keamanan tipe tidak bisa dijamin penuh pada waktu kompilasi. Runtime menutup celah itu dengan pemeriksaan saat penulisan elemen: bila nilai yang ditulis tidak sesuai tipe asli array, runtime melempar ArrayTypeMismatchException.
Contoh: Array dan Pemeriksaan Runtime #
string[] daftarBurung = { "Merpati", "Beo" };
object[] kotakBurung = daftarBurung;
Console.WriteLine(kotakBurung[0]);
try
{
kotakBurung[1] = 42;
}
catch (ArrayTypeMismatchException ex)
{
Console.WriteLine(ex.GetType().Name);
}Output yang Dihasilkan:
Merpati
ArrayTypeMismatchExceptionMari kita bedah baris demi baris:
object[] kotakBurung = daftarBurung;: Array covariance mengizinkan penugasan ini karenastringmewarisiobject; kedua variable menunjuk array yang sama.Console.WriteLine(kotakBurung[0]): Pembacaan lewat tipeobject[]aman, karena setiapstringmemang adalahobject; output menampilkanMerpati.kotakBurung[1] = 42;: Nilaiintbukanstring, dan array yang ditunjuk tetap array string; compiler melewati baris ini, tetapi runtime menolaknya.catch (ArrayTypeMismatchException ex): Penangkap exception mencetak nama tipenya, membuktikan pemeriksaan array terjadi pada waktu eksekusi, bukan waktu kompilasi.
Variance pada Tipe Generic #
Tipe generic tertentu mendeklarasikan arah variance-nya secara eksplisit: parameter tipe out T berarti covariant, sedangkan in T berarti contravariant.
| Parameter tipe | Arah | Contoh tipe | Konversi yang sah |
|---|---|---|---|
out T | Covariant | IEnumerable<out T>, Func<out TResult> | IEnumerable<string> menjadi IEnumerable<object> |
in T | Contravariant | Action<in T> | Action<object> menjadi Action<string> |
Intuisinya: tipe out hanya mengeluarkan nilai, sehingga pengeluaran string aman dipandang sebagai pengeluaran object; tipe in hanya menerima masukan, sehingga penerima object sanggup menerima string apa pun.
string[] daftarBurung = { "Merpati", "Beo" };
IEnumerable<object> bendaBurung = daftarBurung;
foreach (object benda in bendaBurung)
{
Console.WriteLine(benda);
}
Func<string> pembuatPesan = () => "Pesan siap dikirim.";
Func<object> pembuatObjek = pembuatPesan;
Console.WriteLine(pembuatObjek());
Action<object> cetakObjek = isi => Console.WriteLine(isi);
Action<string> cetakTeks = cetakObjek;
cetakTeks("Paket nomor 17 sudah diproses.");Output yang Dihasilkan:
Merpati
Beo
Pesan siap dikirim.
Paket nomor 17 sudah diproses.Baris IEnumerable<object> bendaBurung = daftarBurung; memakai covariance karena T bertanda out; baris Action<string> cetakTeks = cetakObjek; memakai contravariance karena T bertanda in. Ketiga penugasan generic pada contoh lulus kompilasi tanpa peringatan, berbeda dari array yang menunggu pemeriksaan runtime.
Bab berikutnya menggabungkan seluruh mekanisme inheritance menjadi satu teknik inti: runtime polymorphism.