Mengapa saya harus menghindari penggunaan Properties di C #?

102

Dalam bukunya yang luar biasa, CLR Via C #, Jeffrey Richter mengatakan bahwa dia tidak menyukai properti, dan merekomendasikan untuk tidak menggunakannya. Dia memberi beberapa alasan, tapi saya tidak begitu mengerti. Adakah yang bisa menjelaskan kepada saya mengapa saya harus atau tidak boleh menggunakan properti? Di C # 3.0, dengan properti otomatis, apakah ini berubah?

Sebagai referensi, saya menambahkan pendapat Jeffrey Richter:

• Properti mungkin hanya baca atau tulis; akses lapangan selalu dapat dibaca dan ditulis. Jika Anda mendefinisikan properti, yang terbaik adalah menawarkan get dan set accessor method.

• Sebuah metode properti mungkin membuat pengecualian; akses lapangan tidak pernah membuat pengecualian.

• Properti tidak bisa dikirimkan sebagai parameter out atau ref ke metode; sebuah lapangan bisa. Misalnya, kode berikut tidak akan dikompilasi:

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

• Metode properti membutuhkan waktu lama untuk dieksekusi; akses lapangan selalu selesai dengan segera. Alasan umum untuk menggunakan properti adalah untuk melakukan sinkronisasi utas, yang dapat menghentikan utas selamanya, dan oleh karena itu, properti tidak boleh digunakan jika sinkronisasi utas diperlukan. Dalam situasi itu, metode lebih disukai. Selain itu, jika kelas Anda dapat diakses dari jarak jauh (misalnya, kelas Anda diturunkan dari System.MashalByRefObject), memanggil metode properti akan sangat lambat, dan oleh karena itu, metode lebih disukai daripada properti. Menurut pendapat saya, kelas yang diturunkan dari MarshalByRefObject tidak boleh menggunakan properti.

• Jika dipanggil beberapa kali berturut-turut, metode properti dapat mengembalikan nilai yang berbeda setiap kali; sebuah bidang mengembalikan nilai yang sama setiap kali. Kelas System.DateTime memiliki properti Sekarang hanya baca yang mengembalikan tanggal dan waktu saat ini. Setiap kali Anda menanyakan properti ini, ini akan mengembalikan nilai yang berbeda. Ini adalah kesalahan, dan Microsoft berharap mereka dapat memperbaiki kelas dengan menjadikan Now sebagai metode alih-alih properti.

• Metode properti dapat menyebabkan efek samping yang dapat diamati; akses lapangan tidak pernah melakukannya. Dengan kata lain, pengguna suatu tipe harus dapat menyetel berbagai properti yang ditentukan oleh tipe dalam urutan apa pun yang dia pilih tanpa memperhatikan perilaku yang berbeda dalam tipe tersebut.

• Sebuah metode properti mungkin memerlukan memori tambahan atau mengembalikan referensi ke sesuatu yang sebenarnya bukan bagian dari status objek, jadi memodifikasi objek yang dikembalikan tidak berpengaruh pada objek asli; membuat kueri bidang selalu mengembalikan referensi ke objek yang dijamin menjadi bagian dari status objek asli. Bekerja dengan properti yang mengembalikan salinan bisa sangat membingungkan pengembang, dan karakteristik ini sering kali tidak didokumentasikan.

Quan Mai
sumber
11
Saya memiliki edisi ke-3 'CLR via C #' dan pada halaman 242 Tuan Richter mengatakan bahwa dia secara pribadi tidak menyukai properti, tetapi dia tidak pernah merekomendasikan untuk tidak menggunakannya. Harap kutip versi buku dan nomor halaman tempat Anda membaca ini.
kirk.burleson

Jawaban:

173

Alasan Jeff untuk tidak menyukai properti adalah karena terlihat seperti bidang - jadi pengembang yang tidak memahami perbedaannya akan memperlakukannya seolah-olah itu bidang, dengan asumsi bahwa mereka akan murah untuk dieksekusi, dll.

Secara pribadi saya tidak setuju dengan dia dalam hal ini - saya menemukan properti membuat kode klien lebih mudah dibaca daripada panggilan metode yang setara. Saya setuju bahwa pengembang perlu mengetahui bahwa properti pada dasarnya adalah metode yang disamarkan - tetapi menurut saya, mendidik pengembang tentang hal itu lebih baik daripada membuat kode lebih sulit untuk dibaca menggunakan metode. (Secara khusus, setelah melihat kode Java dengan beberapa getter dan setter dipanggil dalam pernyataan yang sama, saya tahu bahwa kode C # yang setara akan jauh lebih sederhana untuk dibaca. Hukum Demeter semuanya sangat baik secara teori, tetapi terkadang foo.Name.Lengthmemang demikian hal yang benar untuk digunakan ...)

(Dan tidak, properti yang diterapkan secara otomatis tidak benar-benar mengubah semua ini.)

Ini sedikit seperti argumen yang menentang penggunaan metode ekstensi - saya dapat memahami alasannya, tetapi manfaat praktis (bila digunakan dengan hemat) melebihi sisi negatifnya dalam pandangan saya.

Jon Skeet
sumber
Terima kasih banyak atas jawaban Anda! Tentang argumen yang menentang penggunaan metode penyuluhan: apakah Anda berbicara tentang beberapa topik Jeffrey Richter atau secara abstrak?
abatishchev
@abatishchev: Itu hanya poin umum tentang metode penyuluhan. Ini tidak terkait langsung dengan properti.
Jon Skeet
Aku akan melangkah lebih jauh. Kecuali untuk aspek kinerja, saya tidak mengerti mengapa seorang programmer harus TAHU jika sesuatu adalah bidang, atau properti. Dia harus menganggapnya sebagai atribut instance yang menunjukkan STATE instance objek, dan implementasi objek harus menangani semua modifikasi statusnya (dalam kontrak kelas). Jadi properti bisa saja menjadi field dalam beberapa kasus, atau menjadi field pada kasus lain, jika mungkin desain ulang implementasi kelas dilakukan. Kemudian, memutuskan antara bidang atau properti adalah soal seberapa besar perlindungan yang dibutuhkan negara agar tetap konsisten.
TheBlastOne
1
@PatrickFromberg: Tampaknya Anda melewatkan banyak kode yang menggunakan bidang hanya-baca. Tidak ada yang bisa dikatakan bahwa properti menyiratkan perubahan. Saya sering memiliki bidang hanya-baca yang mendukung properti hanya-baca - apakah menurut Anda itu hal yang buruk?
Jon Skeet
1
@Patrick: Tidak, ini membawa manfaat memisahkan API dari implementasi - Anda nanti dapat mengubah bagaimana properti dihitung dari lapangan (misalnya untuk menghitung dua properti terkait dari satu bidang).
Jon Skeet
34

Baiklah, mari kita bahas argumennya satu per satu:

Sebuah properti bisa jadi hanya baca atau tulis; akses lapangan selalu dapat dibaca dan ditulis.

Ini adalah kemenangan untuk properti, karena Anda memiliki kontrol akses yang lebih cermat.

Sebuah metode properti mungkin memunculkan pengecualian; akses lapangan tidak pernah membuat pengecualian.

Meskipun ini sebagian besar benar, Anda bisa memanggil metode pada bidang objek yang tidak diinisialisasi, dan memiliki pengecualian yang dilemparkan.

• Properti tidak bisa dikirimkan sebagai parameter out atau ref ke metode; sebuah lapangan bisa.

Adil.

• Metode properti membutuhkan waktu lama untuk dieksekusi; akses lapangan selalu selesai dengan segera.

Ini juga membutuhkan sedikit waktu.

• Jika dipanggil beberapa kali berturut-turut, metode properti dapat mengembalikan nilai yang berbeda setiap kali; sebuah bidang mengembalikan nilai yang sama setiap kali.

Tidak benar. Bagaimana Anda tahu bahwa nilai bidang tidak berubah (mungkin oleh utas lain)?

Kelas System.DateTime memiliki properti Sekarang hanya baca yang mengembalikan tanggal dan waktu saat ini. Setiap kali Anda menanyakan properti ini, ini akan mengembalikan nilai yang berbeda. Ini adalah kesalahan, dan Microsoft berharap mereka dapat memperbaiki kelas dengan menjadikan Now sebagai metode alih-alih properti.

Jika itu adalah kesalahan, itu kecil.

• Metode properti dapat menyebabkan efek samping yang dapat diamati; akses lapangan tidak pernah melakukannya. Dengan kata lain, pengguna suatu tipe harus dapat menyetel berbagai properti yang ditentukan oleh tipe dalam urutan apa pun yang dia pilih tanpa memperhatikan perilaku yang berbeda dalam tipe tersebut.

Adil.

• Sebuah metode properti mungkin memerlukan memori tambahan atau mengembalikan referensi ke sesuatu yang sebenarnya bukan bagian dari status objek, jadi memodifikasi objek yang dikembalikan tidak berpengaruh pada objek asli; membuat kueri bidang selalu mengembalikan referensi ke objek yang dijamin menjadi bagian dari status objek asli. Bekerja dengan properti yang mengembalikan salinan bisa sangat membingungkan pengembang, dan karakteristik ini sering kali tidak didokumentasikan.

Sebagian besar protes juga dapat dikatakan untuk getter dan setter Java —dan kami melakukannya cukup lama tanpa masalah seperti itu dalam praktiknya.

Saya pikir sebagian besar masalah dapat diselesaikan dengan penyorotan sintaks yang lebih baik (yaitu membedakan properti dari bidang) sehingga programmer tahu apa yang diharapkan.

Hejazzman
sumber
3
"masalah dapat diselesaikan dengan penyorotan sintaks yang lebih baik" : Seberapa sering Anda menggunakan kolom publik? Bidang pribadi biasanya memiliki gaya yang berbeda, mis _field. Atau bahkan hanya huruf kecil field.
Steven Jeuris
18

Saya belum membaca bukunya, dan Anda belum mengutip bagiannya yang tidak Anda mengerti, jadi saya harus menebaknya.

Beberapa orang tidak menyukai properti karena mereka dapat membuat kode Anda melakukan hal-hal yang mengejutkan.

Jika saya mengetik Foo.Bar, orang yang membacanya biasanya berharap ini hanya mengakses bidang anggota kelas Foo. Ini operasi yang murah, hampir gratis, dan deterministik. Saya dapat menyebutnya berulang kali, dan mendapatkan hasil yang sama setiap saat.

Sebaliknya, dengan properti, ini mungkin sebenarnya adalah panggilan fungsi. Ini mungkin putaran tak terbatas. Ini mungkin membuka koneksi database. Ini mungkin mengembalikan nilai yang berbeda setiap kali saya mengaksesnya.

Ini adalah argumen yang mirip dengan mengapa Linus membenci C ++. Kode Anda bisa mengejutkan pembaca. Dia membenci operator yang kelebihan beban: a + btidak selalu berarti penambahan sederhana. Ini mungkin berarti beberapa operasi yang sangat rumit, seperti properti C #. Ini mungkin memiliki efek samping. Itu bisa melakukan apa saja.

Sejujurnya, saya pikir ini argumen yang lemah. Kedua bahasa itu penuh dengan hal-hal seperti ini. (Haruskah kita menghindari operator overloading di C # juga? Bagaimanapun, argumen yang sama dapat digunakan di sana)

Properti memungkinkan abstraksi. Kita dapat berpura - pura bahwa sesuatu adalah bidang biasa, dan menggunakannya seolah-olah itu adalah satu bidang, dan tidak perlu khawatir tentang apa yang terjadi di balik layar.

Itu biasanya dianggap sebagai hal yang baik, tetapi jelas bergantung pada programmer yang menulis abstraksi yang bermakna. Properti Anda harus berperilaku seperti bidang. Mereka seharusnya tidak memiliki efek samping, mereka tidak boleh melakukan operasi yang mahal atau tidak aman. Kami ingin bisa menganggapnya sebagai ladang.

Namun, saya punya alasan lain untuk menemukan mereka kurang sempurna. Mereka tidak dapat diteruskan dengan mengacu pada fungsi lain.

Bidang dapat dilewatkan sebagai ref, memungkinkan fungsi yang dipanggil untuk mengaksesnya secara langsung. Fungsi dapat diberikan sebagai delegasi, memungkinkan fungsi yang dipanggil untuk mengaksesnya secara langsung.

Properti ... tidak bisa.

Itu menyebalkan.

Tetapi itu tidak berarti properti itu jahat atau tidak boleh digunakan. Untuk banyak tujuan, mereka hebat.

jalf
sumber
3
Argumen saya adalah bahwa Anda tidak boleh berasumsi bahwa ini adalah bidang untuk memulai - karena jika Anda memanggilnya dari kelas lain, Anda tidak boleh memiliki akses ke bidang non-konstan, karena harus bersifat pribadi. (Ada juga konvensi penamaan untuk memberi tahu Anda.)
Jon Skeet
1
Ya saya setuju. Argumennya tampaknya bermuara pada "Saya terbiasa dengan sintaks ini yang hanya digunakan untuk bidang. Oleh karena itu, memperluasnya untuk mencakup kasus lain itu buruk". Dan jawaban yang jelas adalah "Baiklah, biasakanlah untuk mencakup kasus-kasus lain, dan itu tidak akan buruk". ;)
jalf
Saya berharap bahasa .net akan menyediakan sarana standar dimana kelas mengekspos properti sebagai refparams; anggota (misalnya Foo) dari formulir void Foo<T>(ActionByRef<Point,T> proc, ref T param)dengan atribut khusus, dan kompilator diubah thing.Foo.X+=someVar;menjadi Foo((ref Point it, ref int param)=>it.X += param, ref someVar);. Karena lambda adalah delegasi statis, tidak ada penutupan yang diperlukan, dan pengguna suatu objek akan dapat menggunakan lokasi penyimpanan apa pun yang mendukung properti sebagai refparameter asli (dan dapat meneruskannya ke metode lain sebagai refparameter).
supercat
Menulis lambda dengan tangan menghasilkan kode sumber yang tampak menjijikkan, tetapi itulah mengapa meminta kompilator melakukan transformasi akan sangat membantu. Kode untuk kelas untuk mengekspos properti "callback-by-ref" akan cukup masuk akal. Kode hanya jelek (tidak ada transformasi) di sisi pemanggil.
supercat
Harap dipahami bahwa properti adalah panggilan fungsi yang menyamar sebagai anggota, jadi properti tidak dapat diteruskan dengan referensi seperti halnya Anda dapat meneruskan fungsi publik kelas. Anda selalu dapat menggunakan anggota publik jika Anda berniat melakukannya dengan cara itu. Sebuah properti adalah anggota cerdas, itu bisa melempar pengecualian untuk data tidak valid yang diteruskan ke set.
Diceyus
17

Kembali pada tahun 2009, saran ini hanya tampak seperti sakit perut dari varietas Who Moved My Cheese . Hari ini, itu hampir usang.

Satu hal yang sangat penting yang tampaknya banyak dijawab tetapi tidak cukup dibahas adalah bahwa "bahaya" properti yang diklaim ini merupakan bagian yang disengaja dari desain kerangka kerja!

Ya, properti dapat:

  • Tentukan pengubah akses yang berbeda untuk pengambil dan penyetel. Ini adalah keunggulan dibandingkan ladang. Pola yang umum adalah memiliki pengambil publik dan penyetel yang dilindungi atau internal , teknik pewarisan yang sangat berguna yang tidak dapat dicapai oleh bidang saja.

  • Lempar pengecualian. Sampai saat ini, metode ini tetap menjadi salah satu metode validasi yang paling efektif, terutama saat bekerja dengan framework UI yang melibatkan konsep pengikatan data. Jauh lebih sulit untuk memastikan bahwa suatu objek tetap dalam keadaan valid saat bekerja dengan bidang.

  • Butuh waktu lama untuk mengeksekusinya. Perbandingan yang valid di sini adalah dengan metode , yang membutuhkan waktu yang sama panjangnya - bukan bidang . Tidak ada dasar yang diberikan untuk pernyataan "metode lebih disukai" selain preferensi pribadi satu penulis.

  • Kembalikan nilai yang berbeda dari pengambil pada eksekusi selanjutnya. Ini hampir tampak seperti lelucon yang sangat dekat dengan poin yang memuji kebaikan ref/ outparameter dengan bidang, yang nilainya bidang setelah ref/out panggilan cukup banyak dijamin berbeda dari nilai sebelumnya, dan tidak dapat diprediksi.

    Jika kita berbicara tentang kasus spesifik (dan praktis akademis) akses single-threaded tanpa kopling aferen, cukup dipahami dengan baik bahwa itu hanya desain properti yang buruk untuk memiliki efek samping yang terlihat-berubah, dan mungkin ingatan saya adalah memudar, tetapi saya tidak bisa mengingat contoh orang yang menggunakan DateTime.Nowdan mengharapkan nilai yang sama muncul setiap saat. Setidaknya tidak ada contoh di mana mereka tidak akan mengacaukannya sama buruknya dengan hipotesis DateTime.Now().

  • Menyebabkan efek samping yang dapat diamati - yang tentu saja merupakan alasan mengapa properti diciptakan sebagai fitur bahasa sejak awal. Pedoman Desain Properti Microsoft sendiri menunjukkan bahwa urutan penyetel seharusnya tidak menjadi masalah, karena jika tidak, akan menyiratkan penggandengan sementara . Tentu saja, Anda tidak dapat mencapai penggandengan sementara dengan bidang saja, tetapi itu hanya karena Anda tidak dapat menyebabkan perilaku yang berarti terjadi dengan bidang saja, hingga beberapa metode dijalankan.

    Pengakses properti sebenarnya dapat membantu mencegah jenis kopling temporal tertentu dengan memaksa objek ke dalam keadaan valid sebelum tindakan apa pun diambil - misalnya, jika kelas memiliki a StartDatedan EndDate, kemudian menyetel EndDatesebelum StartDatedapat memaksa StartDatemundur juga. Ini berlaku bahkan di lingkungan multi-utas atau asinkron, termasuk contoh nyata dari antarmuka pengguna yang digerakkan oleh peristiwa.

Hal-hal lain yang dapat dilakukan properti yang tidak dapat disertakan bidang:

  • Pemuatan lambat , salah satu cara paling efektif untuk mencegah kesalahan urutan inisialisasi.
  • Ubah Pemberitahuan , yang merupakan dasar dari arsitektur MVVM .
  • Pewarisan , misalnya mendefinisikan abstrak Typeatau Namekelas turunan dapat memberikan metadata yang menarik namun tetap konstan tentang dirinya.
  • Intersepsi , berkat yang di atas.
  • Pengindeks , yang setiap orang pernah bekerja dengan interop COM dan semburan Item(i)panggilan yang tak terhindarkan akan mengenali sebagai hal yang luar biasa.
  • Bekerja dengan PropertyDescriptor yang penting untuk membuat desainer dan kerangka kerja XAML secara umum.

Richter jelas seorang penulis yang produktif dan tahu banyak tentang CLR dan C #, tetapi saya harus mengatakan, sepertinya ketika dia pertama kali menulis saran ini (saya tidak yakin apakah itu dalam revisi yang lebih baru - saya sangat berharap tidak) bahwa dia hanya tidak ingin melepaskan kebiasaan lamanya dan mengalami kesulitan menerima konvensi C # (vs. C ++, misalnya).

Yang saya maksud dengan ini adalah, argumen "properti dianggap berbahaya" pada dasarnya bermuara pada satu pernyataan: Properti tampak seperti bidang, tetapi mungkin tidak bertindak seperti bidang. Dan masalah dengan pernyataan itu adalah, itu tidak benar , atau paling-paling itu sangat menyesatkan. Properti tidak terlihat seperti bidang - setidaknya, tidak seharusnya terlihat seperti bidang.

Ada dua konvensi pengkodean yang sangat kuat di C # dengan konvensi serupa yang dimiliki oleh bahasa CLR lainnya, dan FXCop akan berteriak pada Anda jika Anda tidak mengikutinya:

  1. Kolom harus selalu bersifat pribadi, bukan untuk publik.
  2. Bidang harus dideklarasikan dalam camelCase. Properti adalah PascalCase.

Jadi, tidak ada ambiguitas mengenai apakah Foo.Bar = 42itu pengakses properti atau pengakses lapangan. Ini adalah pengakses properti dan harus diperlakukan seperti metode lainnya - mungkin lambat, mungkin akan memunculkan pengecualian, dll. Itulah sifat Abstraksi - sepenuhnya tergantung pada kebijaksanaan kelas yang mendeklarasikan cara bereaksi. Desainer kelas harus menerapkan prinsip paling tidak mengejutkan tetapi penelepon tidak boleh berasumsi apa pun tentang properti kecuali properti tersebut melakukan apa yang tertulis di kemasan. Itu sengaja.

Alternatif untuk properti adalah metode pengambil / penyetel di mana-mana. Itulah pendekatan Java, dan sudah kontroversial sejak awal . Tidak apa-apa jika itu tas Anda, tetapi itu bukan cara kami bergabung di kamp .NET. Kami mencoba, setidaknya dalam batasan sistem yang diketik secara statis, untuk menghindari panggilan Fowler Noise Sintaksis . Kami tidak ingin tanda kurung ekstra, ekstra get/ setkutil, atau tanda tangan metode tambahan - tidak jika kami dapat menghindarinya tanpa kehilangan kejelasan.

Katakan apapun yang kamu suka, tapi foo.Bar.Baz = quux.Answers[42] itu akan selalu jauh lebih mudah dibaca daripada foo.getBar().setBaz(quux.getAnswers().getItem(42)). Dan saat Anda membaca ribuan baris ini setiap hari, itu membuat perbedaan.

(Dan jika tanggapan alami Anda terhadap paragraf di atas adalah mengatakan, "pasti sulit dibaca, tetapi akan lebih mudah jika Anda membaginya menjadi beberapa baris", maka saya minta maaf untuk mengatakan bahwa Anda benar - benar melewatkan intinya .)

Aaronaught
sumber
11

Saya tidak melihat alasan mengapa Anda tidak boleh menggunakan Properti secara umum.

Properti otomatis di C # 3+ hanya menyederhanakan sintaks sedikit (a la syntatic sugar).

Konstantin Tarkus
sumber
tolong, baca halaman 215-216 di buku itu. Saya yakin Anda tahu siapa Jeffrey Richter!
Quan Mai
Saya telah membaca (CLR via C #, 2nd Ed.), Tidak setuju dengan posisinya dan tidak melihat alasan sebenarnya untuk tidak menggunakan properti!
abatishchev
Ini buku yang bagus, tapi saya tidak setuju dengan penulisnya saat ini.
Konstantin Tarkus
Di mana tepatnya tempat di mana penulis menyarankan untuk tidak menggunakan Properties? Belum menemukan apa pun di hal.215-217
Konstantin Tarkus
Saya menambahkan pendapat Jeffrey dalam pertanyaan saya :). Anda dapat menemukannya di halaman 215-216 dalam edisi cetak :)
Quan Mai
9

Itu hanya pendapat satu orang. Saya telah membaca beberapa c # buku dan saya belum pernah melihat orang lain mengatakan "jangan gunakan properti".

Menurut saya pribadi, properti adalah salah satu hal terbaik tentang c #. Mereka memungkinkan Anda untuk mengekspos keadaan melalui mekanisme apa pun yang Anda suka. Anda dapat dengan malas memberi contoh saat pertama kali sesuatu digunakan dan Anda dapat melakukan validasi pada pengaturan nilai dll. Saat menggunakan dan menulisnya, saya hanya memikirkan properti sebagai penyetel dan pengambil yang sintaksnya jauh lebih baik.

Adapun keberatan dengan properti, ada pasangan. Salah satunya mungkin adalah penyalahgunaan properti, yang lainnya mungkin tidak kentara.

Pertama, properti adalah jenis metode. Mengejutkan jika Anda menempatkan logika yang rumit dalam sebuah properti karena sebagian besar pengguna kelas akan mengharapkan properti tersebut menjadi cukup ringan.

Misalnya

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

Saya menemukan bahwa menggunakan metode untuk kasus ini membantu membuat perbedaan.

Kedua, dan yang lebih penting, properti dapat memiliki efek samping jika Anda mengevaluasinya saat melakukan debug.

Katakanlah Anda memiliki beberapa properti seperti ini:

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

Sekarang misalkan Anda memiliki pengecualian yang terjadi ketika terlalu banyak kueri dibuat. Tebak apa yang terjadi ketika Anda mulai men-debug dan menggulirkan properti di debugger? Hal buruk. Hindari melakukan ini! Melihat properti mengubah status program.

Ini adalah satu-satunya peringatan yang saya miliki. Menurut saya, manfaat properti jauh lebih penting daripada masalahnya.

Mark Simpson
sumber
6

Alasan itu pasti diberikan dalam konteks yang sangat spesifik. Biasanya sebaliknya - disarankan untuk menggunakan properti karena properti memberi Anda tingkat abstraksi yang memungkinkan Anda mengubah perilaku kelas tanpa memengaruhi kliennya ...

Rashack
sumber
+1 untuk secara implisit menyoroti pentingnya "kontrak" antara klien dan properti kelas.
TheBlastOne
6

Saya tidak bisa tidak memilih detail dari pendapat Jeffrey Richter:

Sebuah properti bisa jadi hanya baca atau tulis; akses lapangan selalu dapat dibaca dan ditulis.

Salah: Bidang dapat ditandai hanya-baca sehingga hanya konstruktor objek yang dapat menulis padanya.

Sebuah metode properti mungkin memunculkan pengecualian; akses lapangan tidak pernah membuat pengecualian.

Salah: Implementasi kelas dapat mengubah pengubah akses suatu bidang dari publik menjadi pribadi. Upaya untuk membaca bidang pribadi pada waktu proses akan selalu menghasilkan pengecualian.

Cecil Memiliki Nama
sumber
5

Saya tidak setuju dengan Jeffrey Richter, tapi saya bisa menebak mengapa dia tidak menyukai properti (saya belum membaca bukunya).

Meskipun, properti hanya seperti metode (penerapannya), sebagai pengguna kelas, saya berharap propertinya berperilaku "lebih atau kurang" seperti bidang publik, misalnya:

  • tidak ada operasi yang memakan waktu di dalam pengambil / penyetel properti
  • pengambil properti tidak memiliki efek samping (menyebutnya beberapa kali, tidak mengubah hasil)

Sayangnya, saya telah melihat properti yang tidak berperilaku seperti itu. Tapi masalahnya bukan pada properti itu sendiri, tetapi orang yang menerapkannya. Jadi itu hanya membutuhkan pendidikan.

M4N
sumber
1
+1 karena ini menyoroti pentingnya kontrak yang bersih. Memiliki properti yang tampaknya hanya-baca yang secara teratur mengembalikan nilai yang berbeda pada setiap referensi adalah properti readwrite - itu tidak hanya menulis pada nilainya sendiri, tetapi variabel instan lainnya (secara langsung atau tidak langsung). Itu bukan gaya yang buruk, tetapi harus didokumentasikan (atau menjadi bagian tersirat dari kontrak).
TheBlastOne
4

Ada saat ketika saya mempertimbangkan untuk tidak menggunakan properti, dan itu ada dalam penulisan kode .Net Compact Framework. Kompilator CF JIT tidak melakukan pengoptimalan yang sama seperti kompiler JIT desktop dan tidak mengoptimalkan pengakses properti sederhana, jadi dalam kasus ini menambahkan properti sederhana menyebabkan sejumlah kecil kode membengkak saat menggunakan bidang publik. Biasanya ini tidak akan menjadi masalah, tetapi hampir selalu di dunia Compact Framework Anda menghadapi kendala memori yang ketat, jadi bahkan penghematan kecil seperti ini akan dihitung.

Steve
sumber
4

Anda tidak boleh menghindari penggunaannya tetapi Anda harus menggunakannya dengan kualifikasi dan perhatian, untuk alasan yang diberikan oleh kontributor lain.

Saya pernah melihat properti bernama sesuatu seperti Pelanggan yang secara internal membuka panggilan di luar proses ke database dan membaca daftar pelanggan. Kode klien memiliki 'for (int i to Customers.Count)' yang menyebabkan panggilan terpisah ke database pada setiap iterasi dan untuk akses Pelanggan yang dipilih. Itu adalah contoh mengerikan yang mendemonstrasikan prinsip menjaga properti sangat ringan - jarang lebih dari akses lapangan internal.

Satu argumen UNTUK menggunakan properti adalah bahwa properti memungkinkan Anda untuk memvalidasi nilai yang sedang ditetapkan. Lain adalah bahwa nilai properti dapat berupa nilai turunan, bukan satu bidang, seperti TotalValue = jumlah * kuantitas.

Rob Kent
sumber
3

Secara pribadi saya hanya menggunakan properti saat membuat metode get / set sederhana. Saya menyimpang darinya ketika datang ke struktur data yang rumit.

Steve
sumber
3

Argumen tersebut mengasumsikan bahwa properti itu buruk karena terlihat seperti bidang, tetapi dapat melakukan tindakan yang mengejutkan. Asumsi ini dibatalkan oleh ekspektasi pemrogram .NET:

Properti tidak terlihat seperti bidang. Bidang terlihat seperti properti.

• Sebuah metode properti mungkin membuat pengecualian; akses lapangan tidak pernah membuat pengecualian.

Jadi, sebuah field ibarat properti yang dijamin tidak akan pernah memunculkan eksepsi.

• Properti tidak bisa dikirimkan sebagai parameter out atau ref ke metode; sebuah lapangan bisa.

Jadi, bidang itu seperti properti, tetapi memiliki kemampuan tambahan: meneruskan ke metode ref/ outmenerima.

• Metode properti membutuhkan waktu lama untuk dieksekusi; akses lapangan selalu selesai dengan segera. [...]

Jadi, ladang ibarat properti cepat.

• Jika dipanggil beberapa kali berturut-turut, metode properti dapat mengembalikan nilai yang berbeda setiap kali; sebuah bidang mengembalikan nilai yang sama setiap kali. Kelas System.DateTime memiliki properti Sekarang hanya baca yang mengembalikan tanggal dan waktu saat ini.

Jadi, bidang itu seperti properti yang dijamin mengembalikan nilai yang sama kecuali bidang itu disetel ke nilai yang berbeda.

• Metode properti dapat menyebabkan efek samping yang dapat diamati; akses lapangan tidak pernah melakukannya.

Sekali lagi, bidang adalah properti yang dijamin tidak akan melakukannya.

• Sebuah metode properti mungkin memerlukan memori tambahan atau mengembalikan referensi ke sesuatu yang sebenarnya bukan bagian dari status objek, jadi memodifikasi objek yang dikembalikan tidak berpengaruh pada objek asli; membuat kueri bidang selalu mengembalikan referensi ke objek yang dijamin menjadi bagian dari status objek asli. Bekerja dengan properti yang mengembalikan salinan bisa sangat membingungkan pengembang, dan karakteristik ini sering kali tidak didokumentasikan.

Yang ini mungkin mengejutkan, tetapi bukan karena properti yang melakukan ini. Sebaliknya, hampir tidak ada yang mengembalikan salinan yang bisa berubah dalam properti, sehingga kasus 0,1% mengejutkan.

milleniumbug.dll
sumber
0

Memanggil metode alih-alih properti sangat mengurangi keterbacaan kode pemanggilan. Di J #, misalnya, menggunakan ADO.NET adalah mimpi buruk karena Java tidak mendukung properti dan pengindeks (yang pada dasarnya adalah properti dengan argumen). Kode yang dihasilkan sangat jelek, dengan panggilan metode tanda kurung kosong di semua tempat.

Dukungan untuk properti dan pengindeks adalah salah satu keunggulan dasar C # dibandingkan Java.

Marty Solomon
sumber