Bidang Publik versus Properti Otomatis

353

Kita sering diberitahu bahwa kita harus melindungi enkapsulasi dengan membuat metode pengambil dan penyetel (properti dalam C #) untuk bidang kelas, alih-alih memaparkan bidang ke dunia luar.

Tetapi ada beberapa kali ketika sebuah bidang hanya ada untuk menyimpan nilai dan tidak memerlukan perhitungan apa pun untuk mendapatkan atau mengatur. Untuk ini kita semua akan melakukan nomor ini:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Yah, aku punya pengakuan, aku tidak tahan menulis semua itu (sungguh, itu tidak harus menulisnya, itu harus melihatnya), jadi aku pergi nakal dan menggunakan bidang publik.

Kemudian muncullah C # 3.0 dan saya melihat mereka menambahkan properti otomatis:

public class Book
{
    public string Title {get; set;} 
}

yang lebih rapi, dan saya berterima kasih untuk itu, tapi sungguh, apa yang berbeda dari hanya membuat bidang publik?

public class Book
{
    public string Title;
}
IJ Kennedy
sumber
6
Saya telah mengonversikan feild menjadi properti agar saya bisa menetapkan breakpoint pada setter
Ian Ringrose
1
Saya cenderung membuat apa pun yang bukan properti pribadi karena menyadari bahwa saya harus merevisi ladang menjadi properti telah menyebabkan sakit kepala yang tidak perlu. Properti, bidang, dan metode. Astaga! menyebut ketidakcocokan yang telah menggigit saya di masa lalu.
Steven Wexler
2
The proppotongan kode membuatnya cepat untuk membuat properti. Cukup ketik proplalu tab.
Tono Nam

Jawaban:

175

Dalam pertanyaan terkait yang saya miliki beberapa waktu lalu, ada tautan ke sebuah posting di blog Jeff, menjelaskan beberapa perbedaan.

Properti vs Variabel Publik

  • Refleksi bekerja secara berbeda pada variabel vs properti, jadi jika Anda mengandalkan refleksi, lebih mudah untuk menggunakan semua properti.
  • Anda tidak dapat melakukan databind terhadap suatu variabel.
  • Mengubah variabel ke properti adalah perubahan besar. Sebagai contoh:

    TryGetTitle(out book.Title); // requires a variable
Michael Stum
sumber
24
"Mengubah variabel ke properti adalah perubahan besar." Ini tentu saja hanya berlaku saat menulis perpustakaan yang dapat digunakan kembali, yang sebagian besar pengembang tidak lakukan.
Steven
30
Juga, properti, bahkan properti otomatis, bisa virtual, di mana bidang tidak bisa. Jadi, kelas dasar dapat memiliki implementasi bidang dukungan sederhana seperti yang dihasilkan oleh kompiler untuk prop otomatis, sedangkan kelas turunan dapat melakukan validasi tambahan atau logika / perhitungan lainnya.
KeithS
28
Juga sebuah bidang adalah variabel dan dapat dilewati oleh referensi ( refatau outkata kunci), sementara properti adalah sepasang pengakses dan tidak dapat diteruskan oleh referensi. Misalnya bool success = TryGetMyTitle(out myBook.Title);penggunaan yang outakan bekerja dengan bidang dan tidak bekerja dengan properti. Ini adalah contoh jelas mengapa perubahan dari bidang ke properti merupakan perubahan besar!
Jeppe Stig Nielsen
2
@KyleBaran Tidak, itu tidak masuk akal karena properti adalah sepasang metode pengaksesor, bukan variabel. Hal yang biasa dilakukan adalah mendeklarasikan variabel lokal (mungkin membaca properti dan memasukkan nilainya ke dalam variabel lokal), meneruskan variabel lokal sebagai ref/ out, dan kemudian mengatur properti ke nilai yang dimiliki variabel lokal. Tetapi kemudian metode yang dipanggil tidak mengakses properti itu sendiri, ia mengakses variabel lokal yang Anda buat di sana.
Jeppe Stig Nielsen
5
@ theberserker Benar, meskipun dalam C # 6 Anda dapat melakukan public int Foo { get; }yang akan membuat properti otomatis dengan bidang dukungan hanya baca.
Michael Stum
83

Mengabaikan masalah API, hal yang saya anggap paling berharga tentang penggunaan properti adalah debugging.

Debugger CLR tidak mendukung titik-titik pemutusan data (sebagian besar debugger asli melakukannya). Oleh karena itu tidak mungkin untuk menetapkan titik istirahat pada membaca atau menulis bidang tertentu di kelas. Ini sangat terbatas dalam skenario debugging tertentu.

Karena properti diimplementasikan sebagai metode yang sangat tipis, dimungkinkan untuk menetapkan breakpoint pada baca dan tulis nilai-nilainya. Ini memberi mereka kaki besar di atas bidang.

JaredPar
sumber
2
Sepuluh tahun kemudian, breakpoint data ada di sini, setidaknya untuk .NET Core :)
Luaan
72

Mengubah dari bidang ke properti akan memutus kontrak (mis. Mengharuskan semua kode referensi untuk dikompilasi ulang). Jadi, ketika Anda memiliki titik interaksi dengan kelas lain - anggota publik (dan umumnya dilindungi), Anda ingin merencanakan pertumbuhan di masa depan. Lakukan dengan selalu menggunakan properti.

Bukan apa-apa untuk menjadikannya properti otomatis hari ini, dan 3 bulan kemudian sadar bahwa Anda ingin menjadikannya malas, dan beri centang nol pada pengambil. Jika Anda telah menggunakan bidang, ini adalah perubahan kompilasi terbaik dan tidak mungkin paling buruk, tergantung pada siapa & apa lagi yang bergantung pada majelis Anda.

Rex M
sumber
9
Saya menyukai jawaban ini karena tidak menggunakan kata-kata 'refleksi', 'antarmuka' atau 'menimpa'. (Sayang sekali tentang 'kontrak')
65

Hanya karena tidak ada yang menyebutkannya: Anda tidak bisa mendefinisikan bidang di Antarmuka. Jadi, jika Anda harus mengimplementasikan antarmuka spesifik yang mendefinisikan properti, properti otomatis terkadang merupakan fitur yang sangat bagus.

MartinStettner
sumber
1
Saya akan mengatakan bahwa jika Anda memerlukan antarmuka yang mendefinisikan properti, itu harus kelas abstrak. Hanya karena c # memungkinkan Anda untuk mendefinisikan properti di antarmuka, tidak berarti Anda harus menggunakannya. Ini desain yang buruk.
Odys
8
@odyodyodys - Saya tidak yakin saya setuju bahwa ini adalah desain yang buruk. Tolong jelaskan alasan Anda?
Zaid Masud
4
@odyodyodys Saya setuju dengan zooone9243: Imp, dari sudut pandang desain, tidak ada perbedaan antara mendeklarasikan properti dan mendeklarasikan pasangan pengambil / penyetel (yang merupakan praktik umum untuk antarmuka).
MartinStettner
22
@ zooone9243, + MartinStettner: Itu 6 bulan yang lalu, saya belajar banyak sejak saat itu. Saya mengambilnya kembali :)
Odys
47

Perbedaan besar yang sering diabaikan dan tidak disebutkan dalam jawaban lain: overriding . Anda dapat mendeklarasikan properti virtual dan menimpanya sementara Anda tidak dapat melakukan hal yang sama untuk bidang anggota publik.

Zaid Masud
sumber
10

Ini semua tentang versi dan stabilitas API. Tidak ada perbedaan, dalam versi 1 - tetapi nanti, jika Anda memutuskan Anda harus menjadikan ini properti dengan beberapa jenis pemeriksaan kesalahan pada versi 2, Anda tidak perlu mengubah API Anda - tidak ada perubahan kode, di mana pun, selain definisi properti.

Reed Copsey
sumber
10

Keuntungan lain dari properti yang diimplementasikan otomatis di bidang publik adalah bahwa Anda dapat membuat set accessors menjadi pribadi atau terlindungi, memberikan kelas objek di mana ia didefinisikan sebagai kontrol yang lebih baik daripada bidang publik.

Arnaldo
sumber
8

Tidak ada yang salah dalam membuat bidang public. Tapi ingat membuat getter/setterdengan privatebidang bukan enkapsulasi. IMO, Jika Anda tidak peduli dengan fitur lain dari Property, Anda mungkin juga membuatnya public.

fastcodejava
sumber
1

Jika Anda memutuskan nanti untuk memeriksa apakah judulnya unik, dengan membandingkan koleksi atau database, Anda bisa melakukannya di properti tanpa mengubah kode apa pun yang bergantung padanya.

Jika Anda hanya menggunakan atribut publik maka Anda akan kurang fleksibel.

Fleksibilitas ekstra tanpa memutus kontrak adalah hal yang paling penting bagi saya tentang penggunaan properti, dan, sampai saya benar-benar membutuhkan fleksibilitas, pembuatan-otomatis paling masuk akal.

James Black
sumber
0

Satu hal yang saya temukan sangat berguna serta semua kode dan alasan pengujian adalah bahwa jika itu adalah properti vs bidang adalah bahwa Visual Studio IDE menunjukkan kepada Anda referensi untuk properti tetapi bukan bidang.

TrtlBoy
sumber
0

Setelah saya melakukan beberapa penelitian

  1. Validasi.
  2. Izinkan menimpa accessor untuk mengubah perilaku properti.
  3. Tujuan debugging. Kami akan dapat mengetahui kapan dan apa yang properti ubah dengan menetapkan breakpoint di accessor.
  4. Kami dapat memiliki set-only lapangan. Misalnya, set publik () dan get pribadi (). Ini tidak mungkin dengan bidang publik.

Itu benar-benar memberi kita lebih banyak kemungkinan dan kemungkinan diperpanjang.

KunYu Tsai
sumber