Untuk menjawab bagian "mengapa" dari pertanyaan tentang mengapa tidak List<T>
, Alasannya adalah bukti masa depan dan kesederhanaan API.
Pemeriksaan masa depan
List<T>
tidak dirancang agar mudah diperluas dengan mensubklasifikasikannya; itu dirancang agar cepat untuk implementasi internal. Anda akan melihat metode di atasnya tidak virtual dan jadi tidak bisa diganti, dan tidak ada kait ke Add
/ Insert
/ Remove
operasi.
Ini berarti bahwa jika Anda perlu mengubah perilaku koleksi di masa mendatang (misalnya untuk menolak objek nol yang orang coba tambahkan, atau untuk melakukan pekerjaan tambahan ketika ini terjadi seperti memperbarui status kelas Anda) maka Anda perlu mengubah jenisnya koleksi yang Anda kembalikan ke subclass yang Anda bisa, yang akan menjadi perubahan antarmuka yang melanggar (tentu saja mengubah semantik hal-hal seperti tidak mengizinkan nol juga bisa menjadi perubahan antarmuka, tetapi hal-hal seperti memperbarui keadaan kelas internal Anda tidak akan menjadi).
Jadi dengan mengembalikan salah satu kelas yang dapat dengan mudah disubklasifikasikan seperti Collection<T>
atau antarmuka seperti IList<T>
, ICollection<T>
atau IEnumerable<T>
Anda dapat mengubah implementasi internal Anda menjadi jenis koleksi yang berbeda untuk memenuhi kebutuhan Anda, tanpa melanggar kode konsumen karena masih dapat dikembalikan sebagai tipe yang mereka harapkan.
Kesederhanaan API
List<T>
mengandung banyak operasi yang bermanfaat seperti BinarySearch
, Sort
dan sebagainya. Namun jika ini adalah koleksi yang Anda paparkan maka kemungkinan Anda mengendalikan semantik dari daftar, dan bukan konsumen. Jadi, sementara kelas Anda secara internal mungkin memerlukan operasi ini, sangat tidak mungkin bahwa konsumen kelas Anda ingin (atau bahkan harus) memanggil mereka.
Dengan demikian, dengan menawarkan kelas koleksi atau antarmuka yang lebih sederhana, Anda mengurangi jumlah anggota yang dilihat pengguna API Anda, dan membuatnya lebih mudah untuk mereka gunakan.
Saya pribadi akan mendeklarasikannya untuk mengembalikan antarmuka daripada koleksi nyata. Jika Anda benar-benar ingin akses daftar, gunakan
IList<T>
. Kalau tidak, pertimbangkanICollection<T>
danIEnumerable<T>
.sumber
We recommend using Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<TKey,TItem> for outputs and properties and interfaces IEnumerable<T>, ICollection<T>, IList<T> for inputs.
CA1002 tampaknya sejalan dengan komentar Krzysztof. Saya tidak bisa membayangkan mengapa koleksi beton akan direkomendasikan sebagai ganti antarmuka, dan mengapa perbedaan antara input / output.ReadOnlyCollection<T>
tidak masuk akal untuk input. Demikian pula,IList<T>
seperti input mengatakan, "Saya perlu Sort () atau anggota lain yang dimiliki IList" yang tidak masuk akal untuk sebuah output. Tapi yang saya maksudkan adalah, mengapa akanICollection<T>
direkomendasikan sebagai input danCollection<T>
sebagai output. Mengapa tidak menggunakanICollection<T>
sebagai output juga seperti yang Anda sarankan?Collection<T>
danReadOnlyCollection<T>
keduanya berasal dariICollection<T>
(yaitu tidak adaIReadOnlyCollection<T>
). Jika Anda mengembalikan antarmuka, tidak jelas yang mana dan apakah dapat dimodifikasi. Bagaimanapun, terima kasih atas masukan Anda. Ini adalah pemeriksaan kewarasan yang baik untuk saya.Saya tidak berpikir ada yang menjawab bagian "mengapa" ... jadi begini. Alasan "mengapa" Anda "harus" menggunakan kata
Collection<T>
ganti aList<T>
adalah karena jika Anda mengekspos huruf aList<T>
, maka siapa pun yang mendapatkan akses ke objek Anda dapat memodifikasi item dalam daftar. PadahalCollection<T>
seharusnya menunjukkan bahwa Anda membuat sendiri metode "Tambah", "Hapus", dll.Anda mungkin tidak perlu khawatir tentang hal itu, karena Anda mungkin mengkodekan antarmuka hanya untuk diri sendiri (atau mungkin beberapa kolega). Inilah contoh lain yang mungkin masuk akal.
Jika Anda memiliki susunan publik, mis:
Anda akan berpikir itu karena hanya ada accessor "get" yang tidak ada yang bisa mengacaukan nilai-nilai, tetapi itu tidak benar. Siapa pun dapat mengubah nilai di dalam sana seperti ini:
Secara pribadi, saya hanya akan menggunakan
List<T>
dalam banyak kasus. Tetapi jika Anda merancang perpustakaan kelas yang akan Anda berikan kepada pengembang acak, dan Anda harus bergantung pada keadaan objek ... maka Anda akan ingin membuat Koleksi Anda sendiri dan menguncinya dari sana: )sumber
Ini sebagian besar tentang abstrak implementasi Anda sendiri daripada mengekspos objek Daftar untuk dimanipulasi secara langsung.
Bukan praktik yang baik untuk membiarkan objek lain (atau orang) mengubah keadaan objek Anda secara langsung. Pikirkan getter / setter properti.
Koleksi -> Untuk koleksi normal,
ReadOnlyCollection -> Untuk koleksi yang tidak boleh dimodifikasi
KeyedCollection -> Saat Anda menginginkan kamus.
Cara memperbaikinya tergantung pada apa yang ingin dilakukan kelas Anda dan tujuan metode GetList (). Bisakah Anda menguraikan?
sumber
ReadOnlyCollection
dua yang lain tidak mematuhinya.GetList()
agar dapat membantunya dengan lebih benar.Collection<T>
membantu dalam abstrak implementasi internal dan mencegah manipulasi langsung daftar internal. Bagaimana?Collection<T>
hanyalah pembungkus, beroperasi pada contoh yang sama berlalu. Ini koleksi dinamis yang dimaksudkan untuk warisan, tidak ada yang lain (jawaban Greg lebih relevan di sini).Dalam kasus seperti ini saya biasanya mencoba untuk mengekspos jumlah implementasi yang paling sedikit yang diperlukan. Jika konsumen tidak perlu tahu bahwa Anda benar-benar menggunakan daftar maka Anda tidak perlu mengembalikan daftar. Dengan kembali saat Microsoft menyarankan Koleksi, Anda menyembunyikan fakta bahwa Anda menggunakan daftar dari konsumen kelas Anda dan mengisolasi mereka terhadap perubahan internal.
sumber
Sesuatu untuk ditambahkan meskipun sudah lama sejak ini diminta.
Ketika jenis daftar Anda berasal dari
List<T>
bukanCollection<T>
, Anda tidak bisa menerapkan metode virtual terlindungi yangCollection<T>
mengimplementasikan. Ini artinya bahwa tipe turunan Anda tidak dapat merespons jika modifikasi dilakukan pada daftar. Ini karenaList<T>
menganggap Anda sadar ketika Anda menambah atau menghapus item. Mampu menanggapi pemberitahuan adalah overhead dan karenanyaList<T>
tidak menawarkannya.Dalam kasus ketika kode eksternal memiliki akses ke koleksi Anda, Anda mungkin tidak dapat mengendalikan kapan suatu item ditambahkan atau dihapus. Karena itu,
Collection<T>
berikan cara untuk mengetahui kapan daftar Anda diubah.sumber
Saya tidak melihat masalah dengan mengembalikan sesuatu seperti
Jika saya mengembalikan salinan data internal yang terputus , atau hasil permintaan data yang terlepas - saya dapat kembali dengan aman
List<TItem>
tanpa memaparkan detail implementasi, dan memungkinkan untuk menggunakan data yang dikembalikan dengan cara yang mudah.Tapi ini tergantung pada jenis konsumen apa yang saya harapkan - jika ini adalah sesuatu seperti data grid saya lebih suka mengembalikan
IEnumerable<TItem>
yang akan menjadi daftar item yang disalin dalam banyak kasus :)sumber
Ya, kelas Collection sebenarnya hanya kelas pembungkus di sekitar koleksi lain untuk menyembunyikan detail implementasi dan fitur lainnya. Saya rasa ini ada hubungannya dengan properti menyembunyikan pola pengkodean dalam bahasa berorientasi objek.
Saya pikir Anda tidak perlu khawatir tentang itu, tetapi jika Anda benar-benar ingin menyenangkan alat analisis kode, lakukan saja hal berikut:
sumber
Collection<T>
melindungi baik itu sendiri maupun koleksi yang mendasarinya sejauh yang saya mengerti.Collection<T>
akan segera melindungi koleksi Anda yang mendasarinya.