List <T> adalah kelas dan mengimplementasikan antarmuka ICollection <T> dan IEnumerable <T> . Juga, ICollection <T> memperluas antarmuka IEnumerable <T>. Mereka tidak dapat dipertukarkan, setidaknya tidak dari semua sudut pandang.
Jika Anda memiliki Daftar <T>, Anda dijamin bahwa objek ini mengimplementasikan metode dan properti yang diperlukan untuk diterapkan oleh antarmuka ICollection <T> dan IEnumerable <T>. Kompiler mengetahuinya dan Anda diizinkan untuk melemparkannya ke ICollection <T> atau IEnumerable <T> secara implisit. Namun, jika Anda memiliki ICollection <T> Anda harus memeriksa secara eksplisit dalam kode Anda terlebih dahulu apakah itu Daftar <T> atau yang lain, mungkin Kamus <T> (di mana T adalah KeyValuePair ) sebelum memberikannya ke apa yang Anda keinginan.
Anda tahu bahwa ICollection memperluas IEnumerable, sehingga Anda bisa melemparkannya ke IEnumerable. Tetapi jika Anda hanya memiliki IEnumerable, sekali lagi Anda tidak dijamin bahwa itu adalah Daftar. Mungkin saja, tetapi bisa juga sesuatu yang lain. Anda harus mengharapkan pengecualian pemain tidak valid jika Anda mencoba untuk melemparkan Daftar <T> ke Kamus <T> misalnya.
Jadi mereka tidak "dipertukarkan".
Juga, ada banyak antarmuka generik, lihat apa yang dapat Anda temukan di System.Collections . namespace umum.
Sunting: mengenai komentar Anda, sama sekali tidak ada penalti kinerja jika Anda menggunakan Daftar <T> atau salah satu antarmuka yang diterapkannya. Anda masih perlu membuat objek baru, periksa kode berikut:
List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;
daftar , myColl , dan myEnum semuanya menunjuk ke objek yang sama. Apakah Anda mendeklarasikannya sebagai Daftar atau ICollection atau IEnumerable, saya masih memerlukan program untuk membuat Daftar. Saya bisa menulis ini:
ICollection<T> myColl = new List<T>();
myColl , saat runtime masih menjadi Daftar.
Namun , ini adalah poin yang paling penting ... untuk mengurangi kopling dan meningkatkan pemeliharaan Anda harus selalu mendeklarasikan variabel dan parameter metode Anda menggunakan penyebut serendah mungkin yang mungkin bagi Anda, apakah itu antarmuka atau kelas abstrak atau konkret.
Bayangkan bahwa satu-satunya hal yang dibutuhkan metode "PerformOperation" adalah untuk menghitung elemen, melakukan pekerjaan dan keluar, dalam hal ini Anda tidak memerlukan ratusan metode yang tersedia di Daftar <T>, Anda hanya perlu apa yang tersedia di IEnumerable <T >, jadi yang berikut harus berlaku:
public void PerformOperation(IEnumerable<T> myEnumeration) { ... }
Dengan melakukan itu, Anda dan pengembang lainnya tahu bahwa objek apa pun dari kelas yang mengimplementasikan antarmuka <n> IEnumerable dapat diberikan ke metode ini. Ini mungkin Daftar, Kamus, atau kelas koleksi khusus yang ditulis pengembang lain.
Jika sebaliknya Anda menentukan Anda secara eksplisit membutuhkan Daftar konkret <T> (dan meskipun jarang terjadi dalam kehidupan nyata, hal itu masih dapat terjadi), Anda dan pengembang lainnya tahu bahwa itu haruslah Daftar atau kelas konkret lain yang mewarisi dari Daftar.