Haruskah Anda membuat properti pribadi?


19
private string mWhatever;

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = value;
    }
}

Saya telah melihat beberapa orang yang membuat properti untuk setiap anggota, pribadi atau tidak ... apakah ini masuk akal? Saya bisa melihatnya masuk akal dalam 1% dari kasus di saat Anda ingin mengontrol akses ke anggota di dalam kelas yang berisi itu karena jika Anda tidak menggunakan properti untuk setiap anggota itu akan menyebabkan ketidakkonsistenan dan memeriksa untuk melihat apakah anggota memiliki akses atau tidak (karena Anda memiliki akses ke keduanya dalam lingkup kelas).

Jawaban:


17

Jawaban singkat: Ya , ketika ada kebutuhan. Jika tidak, gunakan pengambil dan setter Properti Properti yang Diterapkan Otomatisprivate string Whatever { get; set;}

  • Ini sangat berguna Ketika Anda menggunakan pendekatan domain dekat
  • Ini juga berguna ketika logika tertentu harus diperiksa ketika Anda menetapkan nilai

Berikut ini adalah deskripsi lengkap kapan Anda akan menggunakan setter pribadi: C # penggunaan properti .


Ini juga sangat mudah untuk membuat properti publik nanti jika diperlukan.
Tom Pickles

4
Apa itu pendekatan domain dekat ?
Dipotong

1
Saya merujuk pada setter pribadi di properti kelas. Ini harus mencegah akses langsung untuk menetapkan nilai dari objek dan memfasilitasi beberapa pemeriksaan logika sebelum menetapkan nilai.
Yusubov

memiliki variabel pribadi dengan setter / getter publik (bahkan jika itu hanya naif) juga memiliki keuntungan bahwa jika kode Anda dikompilasi ke perpustakaan, tanda tangan akan tetap tidak berubah jika Anda mengganti setter / getter naif Anda dengan yang memiliki sisi efek dll. tetapi jika Anda menggunakan variabel publik sederhana sebagai gantinya, tanda tangan pustaka akan berubah jika Anda mengubahnya menjadi penyetel / pengambil non-naif pribadi. .. yang berarti bahwa jika perpustakaan Anda berubah dengan cara itu maka konsumen perpustakaan Anda perlu melakukan kompilasi ulang.
orion elenzil

12

Beberapa jawaban bagus sudah ada di sini, tetapi saya pikir sebagian besar dari mereka kehilangan satu poin dari pertanyaan Anda:

Saya telah melihat beberapa orang yang membuat properti untuk setiap anggota, pribadi atau tidak ... apakah ini masuk akal?

Saya pikir ini jarang diperlukan sebelumnya, untuk setiap anggota . Dimulai dari

 private string Whatever;

Ketika nanti Anda sampai pada titik di mana Anda perlu enkapsulasi atau breakpoint bersyarat untuk anggota tertentu ini, Anda masih bisa menggantinya dengan properti dengan nama yang sama - dalam banyak kasus tanpa mengubah kode yang digunakan Whatever. Namun berhati-hatilah, ada perbedaan kecil, lihat jawaban Brian Rasmussen di pos SO ini (tautan juga diberikan oleh Emmad Kareem, +1).


+1, juga, Anda benar, sebagian besar jawaban melewatkan poin pertanyaan awal, kami tipikal orang-orang TI :)
NoChance

Refactoring bidang ke properti setelah-fakta adalah mimpi buruk; mengharuskan Anda untuk mengkompilasi ulang semua konsumen. Mengubah properti otomatis untuk mengandung logika khusus sangatlah mudah. Jika bahkan ada sedikit peluang kode melihat refactor, itu akan menjadi jauh lebih sedikit bekerja jika Anda hanya menggunakan properti dari awal.
Dan

@ Dan: di sebagian besar proyek saya telah melihat upaya yang sama, Anda harus mengkompilasi ulang dalam kedua kasus. Namun demikian saya pikir Anda benar bahwa menggunakan properti, terutama properti otomatis, dapat membantu menghindari beberapa masalah subtil dengan refleksi atau penggunaan variabel anggota dalam parameter "keluar".
Doc Brown

@DocBrown Bagaimanapun, itu jelas bukan pernyataan catch-all. Ada banyak alasan untuk membuatnya tetap sederhana dan menggunakan bidang. Namun, jika Anda dapat memprediksi suatu refactor, bahkan masalah-masalah halus pun patut dipertimbangkan.
Dan

7

Salah satu keuntungan terbesar dari pendekatan ini adalah Anda dapat mengontrol kapan variabel Anda berubah .

Pertimbangkan yang berikut ini.
Anda sedang men-debug proyek besar. Metode tertentu melempar pengecualian. Anda menetapkan breakpoint dan Anda mengungkapkan bahwa variabel anggota tertentu memiliki nilai yang salah. Katakanlah kode Anda bergantung pada variabel ini secara luas, dan Anda menemukan ratusan penggunaan tulis ( skenario Spaghetti ). Jadi Anda tidak tahu mana dari penggunaan ini ditugaskan nilai buruk.
Jika kode tersebut multithreaded, debugging dapat menjadi mimpi buruk yang nyata.

Dengan properti, Anda dapat mengatur breakpoint di setter . Dikombinasikan dengan suatu kondisi, ia dapat dipakukan dalam sekali jalan.

VC ++ memiliki data breakpoint , tetapi hanya tersedia untuk kode yang tidak dikelola.


1

Jika Anda tidak menggunakan properti, satu-satunya pilihan Anda adalah menggunakan bidang untuk menyimpan data variabel. Properti dan bidang memiliki perbedaan signifikan. Sebagian besar perbedaan ini ditemukan Fields vs Properties . Saya sarankan Anda mempelajari perbedaan kemudian membuat pilihan Anda sesuai dengan kebutuhan aplikasi Anda. Namun, ingatlah bahwa menggunakan bidang alih-alih properti bukanlah praktik OO yang umum karena sifat dan kekurangannya.


1

Properti pribadi dapat sangat berguna untuk merangkum perilaku hal-hal yang bersifat internal ke kelas Anda. Hanya karena sifatnya pribadi tidak berarti Anda tidak boleh mengambil keuntungan dari gula sintaksis yang diberikan properti kepada Anda.


Namun, contoh yang diberikan adalah yang buruk. Pencari dan setter properti Boilerplate seperti ini hampir selalu merupakan ide yang buruk. Jika Anda menggunakan C # 3.0 atau lebih baru, properti otomatis adalah ide yang jauh lebih baik:

private string Whatever { get; set; };

Ini lebih pendek, lebih bersih, dan lebih mudah dibaca. Bahkan itu hampir tidak lebih lama dari sekedar mendeklarasikan variabel pendukung.

Namun yang paling penting, properti otomatis dapat dikonversi ke properti penuh kapan saja tanpa mengubah semantik program lainnya! Jadi, jika Anda perlu menambahkan validasi atau penanganan kesalahan, Anda dapat melakukannya dengan mudah.


Seperti itu, saya selalu berpikir itu memalukan bahwa Anda tidak dapat memiliki properti hanya baca, untuk menegakkan hanya mampu menulis dengan nilai dalam konstruktor, (Saya lebih suka jenis yang tidak dapat diubah ) tetapi ini ditambahkan dalam C # 6.0 sebagai "Inisialisasi Properti Otomatis", yang memungkinkan Anda melakukan:

private string Whatever { get; } = ...;

atau

private string Whatever { get; };

bersama

    Whatever = ...;

di konstruktor.


0

Ini tidak mutlak diperlukan untuk melakukan ini untuk properti pribadi, tetapi itu memungkinkan untuk memodifikasi bagaimana properti mendapatkan / menetapkan nilai yang mendasarinya tanpa mengubah cara itu diakses.

Misalnya, mengubah cara nilai dasar diatur:

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = string.IsNullOrEmpty(value) ? string.Empty : value;
    }
}

0

Ya

Saya pribadi menggunakan ini sebagai mekanisme caching, dan kami mungkin menyebutnya caching level-properti .

private List<User> users;
private List<User> Users
{
    get
    {
        if(users == null) users = new UserManager().GetUsers();
        return users;
    }
}

Sekarang di tempat lain di dalam kelas saya, saya menggunakan Usersproperti alih-alih usersbidang.

Situasi layak lainnya mungkin ketika Anda ingin menerapkan beberapa logika di lapangan, tetapi secara terpusat di kelas. Dengan demikian Anda bisa membuat GetFoo()metode, atau Fooproperti untuk foobidang.

private string foo;
private string Foo
{
    get
    {
        return "Mr. " + foo;
    }
}

0

Sesuatu yang perlu dipertimbangkan:

Properti aktual adalah detail implementasi. Salah satu tujuan OOP adalah untuk mencoba dan meminimalkan pemaparan detail implementasi yang praktis.

Alasan untuk ini adalah jika Anda menyembunyikan properti dan hanya mengeksposnya melalui getter dan setter, Anda memiliki kontrol yang jauh lebih besar. Misalnya, pengambil Anda dapat memvalidasi inputnya dan mencegah properti disetel ke kondisi tidak valid. Jika kemampuan untuk mengubah nilai sangat penting untuk waktu, maka penyetel juga dapat melindungi hal ini. Sang pengambil, harus mendapatkan nilai aktual menjadi mahal untuk alasan apa pun, dapat melakukan inisialisasi malas dan / atau caching.

Memiliki getter dan setter terbuka dan properti disembunyikan terkadang berarti Anda tidak memerlukan properti sama sekali. Pencari Anda dapat menghitung nilai pada doa, atau mendelegasikan tugas di tempat lain, atau apa pun yang memungkinkannya memenuhi spesifikasinya. Yang penting tentang kelas Anda adalah informasi yang dapat Anda akses darinya, bukan bagaimana informasi itu direpresentasikan secara internal.

Tentu saja, jika tidak ada konsekuensi negatif terhadap apa pun di luar kelas yang dapat mengakses properti secara langsung, maka Anda harus membuatnya publik. Namun menurut pengalaman saya, kasus-kasus seperti itu relatif sedikit dan jarang.


0

Saya tahu ini adalah pertanyaan lama dan semua yang dikatakan @Yusubov benar, tetapi sehubungan dengan poin kedua tentang logika spesifik dalam setter, dan karena saya tidak melihat ada orang yang secara khusus menyebutkan ini, contoh sempurna adalah ketika kelas Anda mengimplementasikan INotifyPropertyChangedantarmuka.

Ini digunakan satu ton di WCF dan Silverlight yang memungkinkan Anda untuk mengetahui kapan properti tertentu telah berubah melalui logika di setter-nya seperti di kelas di bawah ini:

public class Settings : INotifyPropertyChanged
{
    public Settings() 
    { 
        this.CountryField = String.Empty; 
    }

    private string CountryField;
    public string Country
    {
        get { return this.CountryField; }
        set
        {
            if (Object.ReferenceEquals(this.CountryField, value)) { return; }

            this.CountryField = value;
            this.RaisePropertyChanged("Country");
        } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.