Saya tidak mengerti perlunya memiliki penyetel pribadi yang dimulai dengan C # 2.
Memiliki metode penyetel untuk saya memungkinkan pengguna untuk menyetel beberapa variabel di kelas itu. Dengan demikian, kami tidak akan mengekspos variabel langsung ke pengguna. Sebaliknya kami membiarkan mereka melakukannya melalui metode penyetel publik ini.
Ini bagi saya menggunakan "enkapsulasi". Ada beberapa argumen di luar sana yang mengklaim bahwa penyetel pribadi akan membiarkan Anda menerapkan enkapsulasi.
Apakah saya tidak menggunakan enkapsulasi dengan menggunakan metode penyetel publik? Mengapa kita membutuhkan penyetel pribadi?
Apa perbedaan antara kelas yang tidak dapat diubah dan kelas dengan penyetel pribadi?
private File settingsFile = null;
dan kemudian di salah satu konstruktor:if (settingsFile == null) { settingsFile = GetSettingsFile() };
. Refactoring code seperti itu terkadang membuat saya menangis :). Hanya karena Anda dapat menetapkan anggota sebelum konstruktor, tidak berarti Anda harus, karena, dengan banyak konstruktor, ini membuat SULIT untuk mengikuti logika. Penyetel pribadi memaksa Anda untuk menyetel nilai di dalam konstruktor atau nanti.Jawaban:
Secara logis.
Kehadiran penyetel pribadi karena Anda bisa menggunakan properti otomatis:
public int MyProperty { get; set; }
Apa yang akan Anda lakukan jika Anda ingin membuatnya hanya untuk dibaca?
public int MyProperty { get; }
Oh sial!! Saya tidak dapat mengaksesnya dari kelas saya sendiri; Saya harus membuatnya seperti properti biasa:
private int myProperty; public int MyProperty { get { return myProperty; } }
Hmm ... tapi saya kehilangan fitur "Properti Otomatis" ...
public int MyProperty { get; private set; }
AHHH .. itu lebih baik !!
sumber
Oh crap!! I can't access it from my own class
Memulai C # 6.0 ini hanya benar di luar fase inisialisasi. Lihat jawaban saya stackoverflow.com/a/34223746/198797{get; }
TIDAK sama dengan{ get; private set; }
. Untuk cara pertamaproperty.GetSetMethod(true)
kembalinull
dan yang terakhirtrue
. Ini mengejutkan saya.Penyetel pribadi berguna jika Anda memiliki properti hanya baca dan tidak ingin secara eksplisit mendeklarasikan variabel pendukung.
Begitu:
public int MyProperty { get; private set; }
sama dengan:
private int myProperty; public int MyProperty { get { return myProperty; } }
Untuk properti yang tidak diimplementasikan secara otomatis, ini memberi Anda cara yang konsisten untuk menyetel properti dari dalam kelas Anda sehingga jika Anda memerlukan validasi, dll. Anda hanya memilikinya di satu tempat.
Untuk menjawab pertanyaan terakhir Anda, MSDN mengatakan ini pada penyetel pribadi:
Dari halaman MSDN pada properti yang Diimplementasikan Otomatis
sumber
Ini agak sederhana. Penyetel pribadi memungkinkan Anda membuat properti publik atau dilindungi hanya-baca.
Itu dia. Itulah satu-satunya alasan.
Ya, Anda dapat membuat properti read-only dengan hanya menentukan getter, tetapi dengan properti auto-implmenet Anda harus menentukan get dan set, jadi jika Anda ingin properti yang diimplementasikan otomatis menjadi read-only, Anda harus menggunakan penyetel pribadi. Tidak ada cara lain untuk melakukannya.
Memang benar bahwa Private setter tidak dibuat khusus untuk properti read-only yang diimplementasikan secara otomatis, tetapi penggunaannya sedikit lebih esoteris karena alasan lain, sebagian besar berpusat di sekitar properti read-only dan penggunaan refleksi dan serialisasi.
sumber
Dengan pengenalan C # 6.0 dan sintaks untuk Penginisialisasi Properti Otomatis , penyetel pribadi tidak lagi diperlukan untuk properti yang hanya disetel saat inisialisasi, baik sebaris atau di dalam konstruktor.
Sintaks baru ini sekarang dikompilasi:
Properti yang diinisialisasi sebaris
public class MyClass1 { public string MyProperty { get; } = "Aloha!" }
Konstruktor menginisialisasi properti
public class MyClass2 { public string MyProperty { get; } public MyClass2(string myProperty) { MyProperty = myProperty; } }
sumber
Misalnya, kelas faktur memungkinkan pengguna untuk menambah atau menghapus item dari properti Item tetapi tidak mengizinkan pengguna mengubah referensi Item (yaitu, pengguna tidak dapat menetapkan properti Item ke contoh objek daftar item lain).
public class Item { public string item_code; public int qty; public Item(string i, int q) { this.item_code = i; this.qty = q; } } public class Invoice { public List Items { get; private set; } public Invoice() { this.Items = new List(); } } public class TestInvoice { public void Test() { Invoice inv = new Invoice(); inv.Items.Add(new Item("apple", 10)); List my_items = new List(); my_items.Add(new Item("apple", 10)); inv.Items = my_items; // compilation error here. } }
sumber
Katakanlah misalnya, Anda tidak menyimpan variabel aktual melalui properti atau menggunakan nilai untuk menghitung sesuatu.
Dalam kasus seperti ini, Anda dapat membuat metode untuk melakukan penghitungan
private void Calculate(int value) { //... }
Atau Anda dapat melakukannya dengan menggunakan
public int MyProperty {get; private set;}
Dalam kasus tersebut saya akan merekomendasikan untuk menggunakan nanti, sebagai refactor properti setiap elemen anggota utuh.
Selain itu, bahkan jika Anda memetakan properti dengan Variabel. Dalam kasus seperti ini, dalam kode Anda, Anda ingin menulis seperti ini:
public int myprop; public int MyProperty {get { return myprop;}} ... ... this.myprop = 30; ... ... if(this.MyProperty > 5) this.myprop = 40;
Kode di atas terlihat mengerikan karena programmer harus selalu berhati-hati dalam menggunakan MyProperty for Get dan myprop for Set.
Rether untuk konsistensi Anda dapat menggunakan penyetel Pribadi yang membuat Propoerty hanya baca di luar sementara Anda dapat menggunakan penyetelnya di dalam kode Anda.
sumber
Saya pikir beberapa orang telah berdansa tentang ini, tetapi bagi saya, nilai setter pribadi adalah Anda dapat merangkum perilaku properti, bahkan di dalam kelas. Seperti yang dicatat abhishek, jika Anda ingin mengaktifkan peristiwa perubahan properti setiap kali properti berubah, tetapi Anda tidak ingin properti dibaca / ditulis ke publik, Anda harus menggunakan penyetel pribadi, atau Anda harus menaikkan acara di mana pun Anda memodifikasi bidang dukungan. Yang terakhir ini rawan kesalahan karena Anda mungkin lupa. Terkait, jika memperbarui nilai properti menghasilkan beberapa penghitungan yang sedang dilakukan atau bidang lain yang dimodifikasi, atau inisialisasi sesuatu yang lambat, maka Anda juga ingin membungkusnya di penyetel pribadi daripada harus mengingat untuk melakukannya di mana pun Anda membuat penggunaan bidang dukungan.
sumber
Enkapsulasi berarti bahwa status suatu objek hanya terjadi melalui antarmuka yang ditentukan, dan karena itu kelas dapat memastikan bahwa status ini selalu valid dan sesuai dengan tujuan kelas.
Oleh karena itu, dalam beberapa kasus, sangat sesuai dengan prinsip enkapsulasi untuk hanya mengekspos bidang secara publik - semua nilai yang mungkin untuk bidang valid dengan semua nilai yang mungkin dari semua bidang lainnya, dan oleh karena itu pemrogram dapat secara aktif memutuskan untuk mengizinkan bidang tersebut untuk dimanipulasi secara bebas oleh kode luar.
Kasus-kasus ini sebagian besar terbatas pada kelas yang sebagian besar merupakan "data lama biasa". Mereka juga tidak terlalu menarik dalam hal ini, jadi cukup tentang mereka.
Dalam kasus lain, dalam bahasa lain, seseorang akan memiliki metode pengambil dan penyetel, sesuatu seperti
int getId()
mendapatkan nilai danvoid setId(int val)
memperbaruinya.Properti memungkinkan kita menggunakan sintaks yang sama untuk membaca dan menulis melalui metode seperti yang akan kita gunakan untuk membaca dan menulis bidang. Ini adalah gula sintaksis yang baik, meski tidak vital.
(Sebenarnya, karena cara kerja refleksi dan kasus seperti
DataBinder.Eval
itu dapat berguna untuk memiliki properti bahkan ketika bidang akan berfungsi dengan baik, tapi itu masalah lain).Hingga penyetel pribadi diperkenalkan (sebenarnya, yang diubah dengan C # 2 adalah sintaksis untuk memiliki penyetel pribadi dan pengambil publik atau dilindungi di blok yang sama), kita dapat memiliki metode pribadi untuk melakukan pekerjaan penyetel pribadi, jadi setter pribadi tidak terlalu diperlukan. Mereka berguna, jadi meskipun hanya gula sintaksis, mereka cukup berguna.
Enkapsulasi bukanlah masalah apakah penyetel (atau pengambil) Anda publik, pribadi, terlindungi, atau internal, tetapi masalah apakah mereka pantas . Mulailah dengan default setiap bidang menjadi pribadi (dan dalam hal ini
readonly
) dan kemudian jika perlu tambahkan anggota (apakah properti atau metode) yang mengubah bidang tersebut, dan pastikan bahwa objek tetap valid saat berubah . Ini memastikan bahwa kelas ' invariant disimpan, yang berarti aturan yang mendeskripsikan set status yang valid tidak pernah rusak (konstruktor juga membantu dengan memastikannya dimulai dalam status yang valid).Adapun pertanyaan terakhir Anda, menjadi tidak berubah berarti bahwa kelas tidak memiliki penyetel publik, dilindungi atau internal dan tidak ada metode publik, dilindungi atau internal yang mengubah bidang apa pun. Ada derajat ini, di C # ada tiga derajat yang mungkin:
Semua bidang instance kelas adalah
readonly
, bahkan kode pribadi tidak dapat mengubahnya. Itu dijamin tidak dapat diubah (apa pun yang mencoba mengubahnya tidak akan dikompilasi) dan kemungkinan pengoptimalan dapat dilakukan di balik ini.Kelas tidak dapat diubah dari luar karena tidak ada anggota publik yang mengubah apa pun, tetapi tidak dijamin oleh penggunaan
readonly
untuk tidak diubah dari dalam.Kelas tidak dapat diubah seperti yang terlihat dari luar, meskipun beberapa status berubah sebagai detail implementasi. Misal, sebuah field bisa dimoisasi, dan karena itu sementara dari luar sebuah usaha untuk mendapatkannya hanya mengambil nilai yang sama, percobaan pertama tersebut sebenarnya menghitungnya dan kemudian menyimpannya untuk diambil pada percobaan berikutnya.
sumber
Anda memerlukan penyetel pribadi, jika Anda ingin mendukung skenario berikut (tidak hanya untuk ini, tetapi ini harus menunjukkan satu alasan bagus): Anda memiliki Properti yang hanya dapat dibaca di kelas Anda, yaitu hanya kelas itu sendiri yang diizinkan untuk berubah itu, tetapi mungkin mengubahnya setelah membuat instance. Untuk binding, Anda harus mengaktifkan peristiwa PropertyChanged, sebaiknya ini dilakukan di penyetel properti (private). Sebenarnya, Anda bisa mengaktifkan event PropertyChanged-dari tempat lain dalam kelas, tetapi menggunakan penyetel pribadi untuk ini adalah "kewarganegaraan yang baik", karena Anda tidak mendistribusikan pemicu perubahan-properti Anda ke seluruh kelas Anda tetapi menyimpannya di properti, di tempatnya.
sumber
Ya, Anda menggunakan enkapsulasi dengan menggunakan properti, tetapi ada lebih banyak nuansa enkapsulasi daripada hanya mengambil kendali atas bagaimana properti dibaca dan ditulis. Menolak properti untuk disetel dari luar kelas dapat berguna untuk ketahanan dan performa.
Kelas yang tidak dapat diubah adalah kelas yang tidak berubah setelah dibuat, jadi penyetel pribadi (atau tidak ada penyetel sama sekali) diperlukan untuk melindungi properti.
Penyetel pribadi lebih sering digunakan dengan singkatan properti yang diperkenalkan di C # 3. Dalam C # 2 penyetel sering kali dihilangkan, dan data pribadi diakses langsung saat disetel.
Properti ini:
public int Size { get; private set; }
sama dengan:
private int _size; public int Size { get { return _size; } private set { _size = value; } }
kecuali, nama variabel pendukung dibuat secara internal oleh kompilator, jadi Anda tidak dapat mengaksesnya secara langsung.
Dengan properti singkatan, penyetel pribadi diperlukan untuk membuat properti hanya-baca, karena Anda tidak dapat mengakses variabel dukungan secara langsung.
sumber
get
danset
sebelum C # 2.0. Juga, saya pikir Anda mencampur 2.0 dan 3.0, karena singkatan yang diterapkan otomatis yang Anda maksud adalah 3.0.Contoh use case:
Saya memiliki contoh objek aplikasi
'UserInfo'
yang berisi propertiSessionTokenIDV1
yang tidak ingin saya perlihatkan kepada konsumen di kelas saya.Saya juga membutuhkan kemampuan untuk menetapkan nilai itu dari kelas saya.
Solusi saya adalah merangkum properti seperti yang ditunjukkan dan membuat penyetel menjadi pribadi sehingga saya dapat mengatur nilai token sesi tanpa mengizinkan kode contoh untuk juga mengaturnya (atau bahkan melihatnya dalam kasus saya)
public class UserInfo { public String SessionTokenIDV1 { get; set; } } public class Example { // Private vars private UserInfo _userInfo = new UserInfo(); public string SessionValidV1 { get { return ((_userInfo.SessionTokenIDV1 != null) && (_userInfo.SessionTokenIDV1.Length > 0)) ? "set" : "unset"; } private set { _userInfo.SessionTokenIDV1 = value; } } }
Edit: Edit Tag Kode Tetap: Contoh memiliki kesalahan yang telah diperbaiki
sumber
Penghargaan untuk https://www.dotnetperls.com/property .
penyetel pribadi sama dengan bidang hanya baca. Mereka hanya dapat diatur dalam konstruktor. Jika Anda mencoba mengatur dari luar Anda mendapatkan kesalahan waktu kompilasi.
public class MyClass { public MyClass() { // Set the private property. this.Name = "Sample Name from Inside"; } public MyClass(string name) { // Set the private property. this.Name = name; } string _name; public string Name { get { return this._name; } private set { // Can only be called in this class. this._name = value; } } } class Program { static void Main() { MyClass mc = new MyClass(); Console.WriteLine(mc.name); MyClass mc2 = new MyClass("Sample Name from Outside"); Console.WriteLine(mc2.name); } }
Silakan lihat screen shot di bawah ini ketika saya mencoba mengaturnya dari luar kelas.
sumber