Aplikasi kasir menyimpan daftar item, aplikasi antrean menyimpan urutan pelanggan, dan keduanya sering dikirim ke method yang sama. Kebutuhan itu memunculkan pertanyaan desain: bagaimana sebuah method menerima List<T>, HashSet<T>, maupun koleksi lain tanpa membuat salinan untuk setiap tipe? Jawaban .NET adalah sekumpulan interface standar di namespace System.Collections.Generic. Interface tersebut menjadi kontrak yang dipenuhi hampir semua koleksi, dan menjadi bahasa bersama yang kita pakai sepanjang section ini.
Hierarki Interface Koleksi #
Interface koleksi disusun dari yang paling longgar ke paling ketat. Setiap interface menambah beberapa janji di atas induknya:
| Interface | Janji utama | Contoh member |
|---|---|---|
IEnumerable<T> | Urutan item yang bisa dibaca | GetEnumerator() |
ICollection<T> | Bisa dihitung, ditambah, dihapus | Count, Add, Remove, Clear |
IList<T> | Akses berdasarkan indeks | this[int], Insert, RemoveAt |
IDictionary<TKey, TValue> | Pasangan kunci-nilai | this[TKey], Keys, Values |
IReadOnlyList<T> | Akses indeks tanpa izin menulis | this[int], Count |
List<T> memenuhi IList<T>, ICollection<T>, dan IEnumerable<T> sekaligus, sehingga sebuah List<T> bisa dipandang sebagai tipe kontrak mana pun yang lebih longgar. Dua interface IReadOnlyList<T> dan IReadOnlyDictionary<TKey, TValue> berada di jalur terpisah: keduanya menjanjikan akses baca tanpa memberi member penulisan.
Deklarasi Lewat Interface #
Ketika variabel dideklarasikan dengan tipe interface, program hanya boleh memanggil member yang dijanjikan interface tersebut, meskipun objek aslinya lebih kaya:
IList<string> agendaRapat = new List<string> { "Sprint review", "Retrospektif" };
agendaRapat.Insert(0, "Rundown pagi");
agendaRapat.RemoveAt(1);
ICollection<int> nomorAntrean = new HashSet<int>();
nomorAntrean.Add(101);
nomorAntrean.Add(102);
IDictionary<string, int> stokBarang = new Dictionary<string, int>();
stokBarang["Kopi Robusta"] = 24;
Console.WriteLine($"Agenda pertama: {agendaRapat[0]}");
Console.WriteLine($"Jumlah agenda: {agendaRapat.Count}");
Console.WriteLine($"Jumlah nomor antrean: {nomorAntrean.Count}");
Console.WriteLine($"Stok kopi robusta: {stokBarang["Kopi Robusta"]} kg");Output yang Dihasilkan:
Agenda pertama: Rundown pagi
Jumlah agenda: 2
Jumlah nomor antrean: 2
Stok kopi robusta: 24 kgMari kita bedah baris demi baris:
IList<string> agendaRapat: objekList<string>dipandang sebagai kontrak berindeks, sehinggaInsertdanRemoveAttersedia.ICollection<int> nomorAntrean = new HashSet<int>(): variabel bertipe kontrak tambah-hapus item, meskipun implementasinyaHashSet<T>.stokBarang["Kopi Robusta"] = 24;: indexer dariIDictionary<TKey, TValue>berlaku sama seperti padaDictionary<TKey, TValue>langsung.- Tiga baris
Console.WriteLineterakhir: semua nilai dibaca lewat member kontrak; tidak ada satu pun cast yang diperlukan.
Bab berikutnya membedah kontrak paling dasar pada tabel di atas, yaitu IEnumerable<T> beserta pasangan IEnumerator<T>.