Haruskah Properti memiliki efek samping


19

Haruskah properti di C # memiliki efek samping selain memberitahukan perubahan pada statusnya?

Saya telah melihat properti yang digunakan dalam beberapa cara berbeda. Dari properti yang akan memuat nilai saat pertama kali diakses ke properti yang memiliki efek samping besar seperti menyebabkan pengalihan ke halaman lain.



1
Di antara temuan @ Job, Mengapa saya harus menghindari penggunaan Properti di C #? Pendapat Jeffrey Richter alias sangat relevan untuk pertanyaan ini.
rwong

@rwong Relevan ya tapi sama sekali tidak masuk akal - meskipun demikian harus dibaca (agar mengetahui masalah yang ia soroti). Setidaknya dalam hal ini saya di kamp Skeet.
Apoorv Khurasia

Meskipun ini berkaitan dengan konstruktor, ini juga relevan: programmers.stackexchange.com/a/164255/1996
Jim G.

Jawaban:


40

Saya berasumsi Anda sedang berbicara tentang properti read-only , atau setidaknya pengambil properti , karena setter properti , dalam hampir setiap contoh, akan memiliki efek samping. Kalau tidak, itu tidak terlalu berguna.

Secara umum, desain yang baik mengikuti prinsip paling tidak mengejutkan . Jangan lakukan hal-hal yang penelepon tidak harapkan Anda lakukan, terutama jika hal-hal itu dapat mengubah hasil di masa depan .

Secara umum , itu berarti bahwa pengambil properti tidak boleh memiliki efek samping.

Namun , mari kita berhati-hati tentang apa yang kita maksud dengan "efek samping".

Sebuah efek samping adalah, secara teknis, setiap modifikasi negara. Itu mungkin negara yang dapat diakses publik, atau ... itu mungkin negara yang sepenuhnya pribadi.

Loader malas / ditangguhkan adalah salah satu contoh negara yang hampir secara eksklusif bersifat pribadi. Selama itu bukan tanggung jawab penelepon untuk membebaskan sumber daya itu, maka Anda sebenarnya mengurangi kejutan dan kerumitan secara umum dengan menggunakan inisialisasi yang ditangguhkan. Penelepon biasanya tidak berharap harus secara eksplisit memberi sinyal inisialisasi struktur internal . Jadi, inisialisasi malas tidak melanggar prinsip di atas.

Contoh lain adalah properti yang disinkronkan. Agar suatu metode aman dari thread, seringkali harus dilindungi oleh bagian kritis atau mutex. Memasuki bagian kritis atau mendapatkan mutex adalah efek samping; Anda memodifikasi negara, biasanya negara global . Namun, efek samping ini diperlukan untuk mencegah jenis kejutan yang jauh lebih buruk - kejutan data yang diubah (atau lebih buruk, sebagian dimodifikasi) oleh utas lainnya.

Jadi saya akan sedikit melonggarkan batasan sebagai berikut: Properti membaca seharusnya tidak memiliki efek samping yang terlihat atau efek samping yang mengubah semantik mereka .

Jika tidak ada cara yang mungkin bagi penelepon untuk dipengaruhi oleh, atau bahkan menyadari efek samping, maka efek samping itu tidak membahayakan. Jika tidak mungkin bagi Anda untuk menulis tes untuk memverifikasi keberadaan efek samping tertentu, maka cukup terlokalisasi untuk label sebagai detail implementasi pribadi, dan dengan demikian tidak ada kekhawatiran yang sah untuk dunia luar.

Tapi berhati-hatilah; sebagai aturan praktis, Anda harus mencoba menghindari efek samping, karena sering kali apa yang Anda anggap sebagai detail implementasi pribadi dapat tiba-tiba bocor dan menjadi publik.


2
+1 - jawaban lengkap yang bagus termasuk kasus yang lebih rumit yang mengubah "harus" menjadi "harus ... kecuali ketika ...."
cepat_now

Contoh lain dari efek samping yang dapat diterima pada pengambil: Fungsi logging.
Loren Pechtel

5

Saya akan menjawab pertanyaan Anda dengan pertanyaan: Apa yang terjadi ketika Anda mengubah properti Lebar dari formulir?

Tak jauh dari kepala saya, ini akan:

  • Ubah nilai bidang dukungan.
  • Tembak sebuah acara.
  • Ubah dimensi formulir, laporkan perubahan itu ke window manager, dan minta pengecatan ulang.
  • Beri tahu kontrol pada formulir perubahan sehingga siapa pun dari mereka yang perlu mengubah ukuran atau posisi saat formulir diubah ukurannya dapat melakukannya.
  • Menyebabkan semua kontrol yang berubah menjadi peristiwa api dan memberi tahu manajer jendela bahwa mereka perlu digambar ulang.
  • Mungkin hal-hal lain juga.

(Penafian: Saya adalah pengembang Delphi, bukan pengembang .NET. Ini mungkin tidak 100% akurat untuk C #, tapi saya yakin itu cukup dekat, terutama mengingat seberapa banyak kerangka kerja .NET asli berdasarkan Delphi.)

Semua "efek samping" ini terjadi ketika Anda mengubah properti Lebar pada formulir. Apakah ada di antara mereka yang tampaknya tidak tepat atau salah?


selama itu tidak masuk ke loop tak terbatas yang memanggil dirinya sendiri. Untuk menghindari hal ini, setiap "perubahan" akan dipetakan ke setidaknya tiga peristiwa: satu dipecat sebelum perubahan, satu dipecat saat perubahan, dan satu dipecat setelah selesai.
rwong

5

Lihatlah Aturan Desain Microsoft , terutama salah satunya:

CA1024: Gunakan properti yang sesuai

... Metode adalah kandidat yang baik untuk menjadi properti jika salah satu dari kondisi ini ada:

  • Tidak mengambil argumen dan mengembalikan informasi status suatu objek.
  • Menerima satu argumen untuk mengatur beberapa bagian dari keadaan suatu objek.

Properti harus berperilaku seolah-olah merupakan bidang; jika metode ini tidak bisa, itu tidak boleh diubah ke properti. Metode lebih baik daripada properti dalam situasi berikut:

  • Metode ini melakukan operasi yang memakan waktu. Metode ini terasa lebih lambat daripada waktu yang dibutuhkan untuk mengatur atau mendapatkan nilai suatu bidang.
  • Metode melakukan konversi. Mengakses bidang tidak mengembalikan versi data konversi yang disimpannya.
  • Metode Get memiliki efek samping yang dapat diamati. Mengambil nilai suatu bidang tidak menghasilkan efek samping apa pun.
  • Urutan eksekusi itu penting. Pengaturan nilai suatu bidang tidak bergantung pada terjadinya operasi lain.
  • Memanggil metode dua kali berturut-turut menciptakan hasil yang berbeda.
  • Metode ini statis tetapi mengembalikan objek yang bisa diubah oleh pemanggil. Mengambil nilai suatu bidang tidak memungkinkan pemanggil mengubah data yang disimpan oleh bidang tersebut.
  • Metode mengembalikan array ...

2

Saya percaya properti tidak boleh memiliki efek samping. Namun ada satu pengecualian untuk aturan ini: lazy loading. Jika Anda ingin memuat sesuatu dengan malas di sebuah properti, itu tidak masalah, karena klien tidak dapat memberi tahu pemuatan malas tersebut, dan umumnya tidak peduli.

EDIT : Oh, satu hal lagi - menembakkan sebuah acara yang mengatakan "PropertyXYZ Berubah!" (misalnya INotifyPropertyChanged) - baik-baik saja pada setter.


2

Selain memuat malas yang disebutkan sebelumnya ada juga kasus fungsi logging. Ini akan jarang tetapi tidak keluar dari pertanyaan.


2

Hampir tidak ada yang absolut dalam pemrograman, untuk menjawab pertanyaan Anda, kami perlu melihat beberapa sifat objek yang diinginkan dan melihat apakah itu sesuatu yang berlaku untuk kasus kami

  1. Kami ingin kelas mudah diuji.
  2. Kami ingin kelas mendukung konkurensi
  3. Kami ingin kelas mudah dipikirkan untuk pihak ketiga

Jika kami menjawab ya, beberapa pertanyaan ini, maka mungkin ide yang baik untuk berpikir sangat hati-hati tentang properti dan efek sampingnya. Saya berasumsi bahwa ketika Anda mengatakan efek samping yang Anda maksudkan efek samping sekunder karena memperbarui nilai adalah efek samping itu sendiri.

Semakin banyak efek samping pada umumnya semakin sulit suatu kelas untuk diuji. Semakin banyak efek samping sekunder, konkurensi lebih sulit akan ditangani, tapi itu masalah sulit yang mungkin memerlukan pemikiran desain utama.

Gotcha besar mungkin untuk orang-orang yang memperlakukan kelas Anda sebagai "kotak hitam", itu tidak akan tersedia bahwa beberapa negara telah berubah hanya karena mereka telah membaca properti atau bahwa beberapa properti lainnya berubah karena perubahan lain (yang mungkin menyebabkan untuk memperbarui cascading).

Jadi secara umum tidak, kami ingin properti semudah dan sesederhana mungkin, itu agak tersirat dalam keputusan desain jika tidak akan menjadi metode. Namun seorang programmer yang baik selalu dapat melanggar aturan, pastikan Anda memiliki alasan yang sangat bagus :)

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.