Apakah ada alasan untuk mengekspos koleksi internal sebagai ReadOnlyCollection daripada IEnumerable jika kode panggilan hanya mengulang koleksi?
class Bar
{
private ICollection<Foo> foos;
// Which one is to be preferred?
public IEnumerable<Foo> Foos { ... }
public ReadOnlyCollection<Foo> Foos { ... }
}
// Calling code:
foreach (var f in bar.Foos)
DoSomething(f);
Seperti yang saya lihat, IEnumerable adalah bagian dari antarmuka ReadOnlyCollection dan tidak memungkinkan pengguna untuk mengubah koleksi. Jadi jika antarmuka IEnumberable sudah cukup maka itulah yang akan digunakan. Apakah itu cara yang tepat untuk menalarinya atau apakah saya melewatkan sesuatu?
Terima kasih / Erik
c#
.net
collections
ienumerable
readonly-collection
Erik Öjebo
sumber
sumber
ReadOnlyCollection
jika Anda paranoid, tetapi sekarang Anda tidak terikat pada implementasi tertentu.Jawaban:
Solusi yang lebih modern
Kecuali jika Anda memerlukan koleksi internal yang dapat diubah, Anda dapat menggunakan
System.Collections.Immutable
paket, mengubah jenis bidang Anda menjadi koleksi yang tidak dapat diubah, dan kemudian mengeksposnya secara langsung - dengan asumsiFoo
itu sendiri tidak dapat diubah, tentu saja.Jawaban yang diperbarui untuk menjawab pertanyaan secara lebih langsung
Itu tergantung pada seberapa besar Anda mempercayai kode panggilan. Jika Anda memegang kendali penuh atas semua yang akan memanggil anggota ini dan Anda menjamin bahwa kode tidak akan pernah digunakan:
Maka pasti, tidak ada salahnya jika Anda langsung mengembalikan koleksinya. Saya biasanya mencoba menjadi sedikit lebih paranoid dari itu.
Demikian juga, seperti yang Anda katakan: jika Anda hanya perlu
IEnumerable<T>
, lalu mengapa mengikatkan diri Anda pada sesuatu yang lebih kuat?Jawaban asli
Jika Anda menggunakan .NET 3.5, Anda dapat menghindari membuat salinan dan menghindari transmisi sederhana dengan menggunakan panggilan sederhana ke Lewati:
(Ada banyak opsi lain untuk membungkus secara sepele - hal yang menyenangkan tentang
Skip
over Select / Where adalah bahwa tidak ada delegasi yang dieksekusi tanpa tujuan untuk setiap iterasi.)Jika Anda tidak menggunakan .NET 3.5 Anda dapat menulis pembungkus yang sangat sederhana untuk melakukan hal yang sama:
sumber
ReadOnlyCollection
keICollection
dan kemudian berjalan denganAdd
sukses. Sejauh yang saya tahu, itu tidak mungkin. Theevil.Add(...)
harus melempar kesalahan. dotnetfiddle.net/GII2jWReadOnlyCollection
- saya melemparkanIEnumerable<T>
yang sebenarnya bukan hanya-baca ... itu alih - alih mengeksposReadOnlyCollection
ReadOnlyCollection
alih - alih sebuahIEnumerable
, untuk melindungi dari casting jahat.Jika Anda hanya perlu mengulang melalui koleksi:
maka mengembalikan IEnumerable sudah cukup.
Jika Anda membutuhkan akses acak ke item:
lalu bungkus dalam ReadOnlyCollection .
sumber
System.Collections.Immutable
seperti yang direkomendasikan Jon Skeet sangat valid ketika Anda mengekspos sesuatu yang tidak akan pernah berubah setelah Anda mendapatkan referensi untuk itu. Di sisi lain, jika Anda mengekspos tampilan read-only dari koleksi yang bisa berubah, maka saran ini masih berlaku, meskipun saya mungkin akan mengeksposnya sebagaiIReadOnlyCollection
(yang tidak ada saat saya menulis ini).bar.Foos[17]
denganIReadOnlyCollection
. Satu-satunya perbedaan adalahCount
properti tambahan .public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
bar.Foos[17]
, Anda harus mengeksposnya sebagaiReadOnlyCollection<Foo>
. Jika Anda ingin mengetahui ukuran dan mengulanginya, tunjukkan sebagaiIReadOnlyCollection<Foo>
. Jika Anda tidak perlu mengetahui ukurannya, gunakanIEnumerable<Foo>
. Ada solusi lain dan detail lainnya, tetapi itu di luar cakupan pembahasan jawaban khusus ini.Jika Anda melakukan ini maka tidak ada yang menghentikan pemanggil Anda mentransmisikan IEnumerable kembali ke ICollection dan kemudian memodifikasinya. ReadOnlyCollection menghilangkan kemungkinan ini, meskipun masih memungkinkan untuk mengakses koleksi yang dapat ditulis melalui refleksi. Jika koleksinya kecil maka cara yang aman dan mudah untuk mengatasi masalah ini adalah dengan mengembalikan salinannya.
sumber
Saya menghindari penggunaan ReadOnlyCollection sebanyak mungkin, ini sebenarnya jauh lebih lambat daripada hanya menggunakan Daftar biasa. Lihat contoh ini:
sumber
Terkadang Anda mungkin ingin menggunakan antarmuka, mungkin karena Anda ingin mengejek koleksi selama pengujian unit. Silakan lihat entri blog saya untuk menambahkan antarmuka Anda sendiri ke ReadonlyCollection dengan menggunakan adaptor.
sumber