Saya memiliki pertanyaan "praktik terbaik" tentang OOP di C # (tapi itu semacam berlaku untuk semua bahasa).
Pertimbangkan memiliki kelas pustaka dengan objek yang akan diekspos ke publik, katakanlah melalui accessor properti, tetapi kami tidak ingin publik (orang yang menggunakan kelas pustaka ini) mengubahnya.
class A
{
// Note: List is just example, I am interested in objects in general.
private List<string> _items = new List<string>() { "hello" }
public List<string> Items
{
get
{
// Option A (not read-only), can be modified from outside:
return _items;
// Option B (sort-of read-only):
return new List<string>( _items );
// Option C, must change return type to ReadOnlyCollection<string>
return new ReadOnlyCollection<string>( _items );
}
}
}
Jelas pendekatan terbaik adalah "opsi C", tetapi sangat sedikit objek memiliki varian ReadOnly (dan tentu saja tidak ada kelas yang ditentukan pengguna memilikinya).
Jika Anda adalah pengguna kelas A, apakah Anda mengharapkan perubahan
List<string> someList = ( new A() ).Items;
merambat ke objek asli (A)? Atau tidak apa-apa mengembalikan klon asalkan ditulis begitu dalam komentar / dokumentasi? Saya pikir pendekatan klon ini mungkin menyebabkan bug yang sulit dilacak.
Saya ingat bahwa di C ++ kita bisa mengembalikan objek const dan Anda hanya bisa memanggil metode yang ditandai sebagai const di atasnya. Saya kira tidak ada fitur / pola seperti itu di C #? Jika tidak, mengapa mereka tidak memasukkannya? Saya percaya ini disebut benar const.
Tetapi sekali lagi pertanyaan utama saya adalah tentang "apa yang Anda harapkan" atau bagaimana menangani Opsi A vs B.
sumber
Jawaban:
Selain jawaban Jesse, yang merupakan solusi terbaik untuk koleksi: ide umumnya adalah merancang antarmuka publik A Anda dengan cara sehingga hanya mengembalikannya
tipe nilai (seperti int, dobel, struct)
objek yang tidak dapat diubah (seperti "string", atau kelas yang ditentukan pengguna yang hanya menawarkan metode baca-saja, seperti kelas A Anda)
(hanya jika Anda harus): objek salinan, seperti "Opsi B" Anda menunjukkan
IEnumerable<immutable_type_here>
tidak berubah dengan sendirinya, jadi ini hanya kasus khusus di atas.sumber
Juga perhatikan Anda harus pemrograman ke antarmuka, dan pada umumnya, apa yang ingin Anda kembalikan dari properti itu adalah
IEnumerable<string>
. AList<string>
sedikit tidak-tidak karena itu umumnya bisa berubah dan saya akan melangkah lebih jauh dengan mengatakan bahwaReadOnlyCollection<string>
sebagai pelaksanaICollection<string>
terasa seperti itu melanggar Prinsip Pergantian Liskov.sumber
IEnumerable<string>
persis apa yang diinginkan seseorang di sini.IReadOnlyList<T>
.IList<T>
)Saya mengalami masalah yang sama beberapa waktu lalu dan di bawah ini adalah solusi saya, tetapi itu benar-benar hanya berfungsi jika Anda mengontrol perpustakaan juga:
Mulailah dengan kelas Anda
A
Kemudian dapatkan antarmuka dari ini dengan hanya mendapatkan sebagian dari properti (dan metode membaca apa pun) dan memiliki A mengimplementasikannya
Maka tentu saja ketika Anda ingin menggunakan versi read only, gips sederhana sudah cukup. Ini adalah apa yang Anda solusi C, sungguh, tapi saya pikir saya akan menawarkan metode yang saya capai
sumber
Bagi siapa pun yang menemukan pertanyaan ini dan masih tertarik dengan jawabannya - sekarang ada opsi lain yang terbuka
ImmutableArray<T>
. Inilah beberapa poin mengapa saya pikir lebih baik dari ituIEnumerable<T>
atauReadOnlyCollection<T>
:IEnumerable<T>
ituIEnumerable
atauIReadOnlyCollect
dia tidak bisa berasumsi bahwa itu tidak pernah berubah (dengan kata lain tidak ada jaminan bahwa item koleksi tidak berubah sementara referensi ke koleksi itu tetap tidak berubah)Juga jika APi perlu memberi tahu klien tentang perubahan dalam koleksi saya akan mengekspos suatu peristiwa sebagai anggota yang terpisah.
Perhatikan bahwa saya tidak mengatakan itu
IEnumerable<T>
buruk secara umum. Saya masih menggunakannya ketika meneruskan koleksi sebagai argumen atau mengembalikan koleksi yang diinisialisasi dengan malas (dalam kasus khusus ini masuk akal untuk menyembunyikan jumlah item karena belum diketahui).sumber