Apakah melempar pengecualian dari formulir properti yang buruk?


15

Saya selalu dari pola pikir bahwa properti (yaitu, operasi set / get mereka) harus cepat / langsung dan bebas kegagalan. Anda seharusnya tidak perlu mencoba / mencari-cari atau mengatur properti.

Tapi saya sedang mencari beberapa cara untuk menerapkan keamanan berbasis peran pada properti beberapa objek. Misalnya properti Karyawan. Gaji. Beberapa solusi yang saya jalankan di yang orang lain telah coba (satu khususnya adalah contoh AOP di sini ) melibatkan melemparkan pengecualian jika accessor tidak memiliki izin yang tepat - tetapi ini bertentangan dengan aturan pribadi yang saya miliki untuk waktu yang lama sekarang.

Jadi saya bertanya: apakah saya salah? Apakah ada yang berubah? Sudahkah diterima bahwa properti harus dapat memberikan pengecualian?


1
Ini pertanyaan yang sama pada StackOverflow mendapat lebih banyak perhatian dan jawaban jadi lebih baik.
Roman Starkov

Jawaban:


14

saat Anda menetapkan nilai properti, melemparkan pengecualian pada nilai yang tidak valid tidak masalah

mendapatkan nilai properti seharusnya (hampir) tidak pernah memberikan pengecualian

untuk akses berbasis peran, gunakan antarmuka / fasad yang berbeda / fasad; jangan biarkan orang melihat hal-hal yang tidak bisa mereka miliki!


5

Saya menganggap itu sebagian besar bentuk yang buruk tetapi bahkan Microsoft merekomendasikan untuk menggunakan pengecualian kadang-kadang. Contoh yang baik adalah Stream properti abstrak . Panjang . Sebagai pedoman, saya akan lebih peduli dengan menghindari efek samping pada getter dan membatasi efek samping pada setter.


4

Saya pasti akan berpendapat bahwa ada cacat dalam desain jika Anda merasa perlu untuk membuang pengecualian dari pengambil properti atau pengambil.

Properti adalah abstraksi yang mewakili sesuatu yang hanya berupa nilai . Dan Anda harus dapat menetapkan nilai tanpa takut hal itu dapat menimbulkan pengecualian. *

Jika pengaturan properti menghasilkan efek samping, yang seharusnya benar-benar diterapkan sebagai metode. Dan jika itu tidak menghasilkan efek samping, maka tidak terkecuali harus dibuang.

Salah satu contoh yang telah disebutkan dalam jawaban yang berbeda adalah Stream.Positionproperti. Ini memang menghasilkan efek samping, dan bisa menimbulkan pengecualian. Tapi setter properti ini pada dasarnya hanya pembungkus Stream.Seekyang bisa Anda hubungi.

Secara pribadi, saya percaya bahwa posisi itu seharusnya bukan properti yang dapat ditulisi.

Contoh lain di mana Anda bisa tergoda untuk melempar pengecualian dari properti setter adalah dalam validasi data:

public class User {
    public string Email {
        get { return _email; }
        set { 
            if (!IsValidEmail(value)) throw InvalidEmailException(value);
            _email = value;
        }
    }

Tetapi ada solusi yang lebih baik untuk masalah ini. Perkenalkan jenis yang mewakili alamat email yang valid:

public class Email {
    public Email(string value) {
        if (!IsValidEmail(value)) throw new InvalidEmailException(value);
        ...
    }
    ...
}

public class User {
    public Email Email { get; set; }
}

The EmailMemastikan kelas yang tidak dapat memegang nilai yang bukan alamat email yang valid, dan kelas yang perlu toko email dibebaskan dari tugas memvalidasi mereka.

Ini juga mengarah pada kohesi yang lebih tinggi (indikator desain perangkat lunak yang baik) - pengetahuan tentang apa alamat email itu, dan bagaimana alamat itu divalidasi, hanya ada di Emailkelas, yang hanya memiliki keprihatinan itu.

* ObjectDisposedException adalah satu-satunya pengecualian yang valid (tidak ada kata pun yang dimaksudkan) yang dapat saya pikirkan saat ini.


2

Saya tahu pertanyaan Anda khusus untuk .NET , tetapi karena C # berbagi beberapa sejarah dengan Java, saya pikir Anda mungkin tertarik. saya tidak menyiratkan bahwa karena sesuatu dilakukan di Jawa, itu harus dilakukan dalam C #. Saya tahu keduanya sangat berbeda, terutama dalam hal C # memiliki dukungan tingkat bahasa yang jauh lebih baik untuk properti. Saya hanya memberikan beberapa konteks dan perspektif.

Dari spesifikasi JavaBeans :

Properti terbatas Kadang-kadang ketika terjadi perubahan properti beberapa kacang lain mungkin ingin memvalidasi perubahan dan menolaknya jika tidak sesuai. Kami merujuk ke properti yang menjalani pemeriksaan semacam ini sebagai properti terbatas. Di Java Beans, metode penyetel properti terbatas diperlukan untuk mendukung PropertyVetoException. Dokumen ini untuk pengguna properti terbatas yang berupaya memperbarui mungkin memveto. Jadi properti dengan batasan sederhana mungkin terlihat seperti:

PropertyType getFoo();
void setFoo(PropertyType value) throws PropertyVetoException;

Tolong, ambil semua ini dengan sebutir garam. Spesifikasi JavaBeans sudah tua, dan Properti C # (IMO) merupakan peningkatan besar atas properti berbasis "penamaan konvensi" yang dimiliki Java. Saya hanya mencoba memberikan sedikit konteks, itu saja!


Ini poin yang bagus, tetapi perbedaan antara metode setter dan properti setter ac # cukup signifikan untuk menjadi kasus yang berbeda bagi saya. Demikian juga, pengecualian yang diperiksa di Java memaksa kode panggilan untuk mengetahui bahwa pengecualian dapat dilemparkan, jadi ada sedikit kemungkinan bahwa ini akan mengejutkan siapa pun.
Steven Evers

2

Titik properti adalah Prinsip Akses Seragam , yaitu bahwa nilai harus dapat diakses melalui antarmuka yang sama baik diimplementasikan oleh penyimpanan atau perhitungan. Jika properti Anda melempar pengecualian yang mewakili kondisi kesalahan di luar kendali programmer, jenis yang seharusnya ditangkap dan ditangani, Anda memaksa klien Anda untuk mengetahui bahwa nilai tersebut diperoleh melalui perhitungan.

Di sisi lain, saya tidak melihat masalah dengan menggunakan penegasan atau pengecualian seperti pernyataan yang dimaksudkan untuk menandakan penggunaan API yang salah kepada programmer daripada ditangkap dan ditangani. Dalam kasus ini, jawaban yang benar dari perspektif pengguna API bukan untuk menangani pengecualian (dengan demikian secara implisit peduli tentang apakah nilai diperoleh melalui perhitungan atau penyimpanan). Ini untuk memperbaiki kodenya sehingga objek tidak berakhir dalam keadaan tidak valid atau membuat Anda memperbaiki kode Anda sehingga pernyataan tidak menyala.


Saya tidak melihat bagaimana "Anda memaksa klien Anda untuk mengetahui bahwa nilai diperoleh melalui perhitungan" mengikuti. Tentu saja akses ke penyimpanan juga dapat menimbulkan pengecualian. Bahkan, bagaimana Anda bahkan menentukan perbedaan di antara keduanya?
Timwi

Saya percaya perbedaan yang dibuat adalah bahwa hanya mengambil nilai dari suatu bidang (penyimpanan) dan melakukan sesuatu yang tidak berbahaya dengannya, seperti menempatkannya dalam variabel dari jenis yang sesuai (yaitu tanpa casting), tidak bisa melempar pengecualian. Dalam hal itu pengecualian hanya dapat terjadi jika Anda kemudian melakukan sesuatu dengan nilai tersebut. Jika pengecualian dilemparkan ke pengambil properti, maka dalam kasus itu hanya tindakan mengambil nilai dan menempatkannya dalam variabel dapat menyebabkan pengecualian.
Apprentice Dr. Wily

1

AFAIK, panduan ini terutama berasal dari proses pemikiran bahwa properti mungkin akhirnya digunakan pada desain waktu . (Misalnya properti Teks pada Kotak Teks) Jika properti melemparkan pengecualian ketika seorang desainer mencoba mengaksesnya, VS tidak akan memiliki hari yang baik. Anda akan mendapatkan banyak kesalahan hanya dengan mencoba menggunakan perancang dan untuk perancang UI, mereka tidak akan merender. Ini juga berlaku untuk waktu debug juga, meskipun apa yang akan Anda lihat dalam skenario pengecualian hanya "xxx Exception" dan itu tidak akan mengalahkan VS IIRC.

Untuk POCO, itu tidak akan benar-benar membahayakan, tetapi saya masih malu melakukannya sendiri. Saya pikir orang-orang akan ingin mengakses properti lebih sering, jadi mereka biasanya berbiaya rendah. Properti seharusnya tidak melakukan pekerjaan metode, mereka hanya harus mendapatkan / mengatur beberapa info dan dilakukan dengan itu sebagai aturan umum.


0

Meskipun banyak yang akan tergantung pada konteksnya, saya biasanya akan menghindari memasukkan segala jenis logika yang dapat pecah (termasuk pengecualian) ke properti. Sama seperti satu contoh, ada banyak hal yang dapat Anda (atau pustaka yang Anda gunakan) dapat lakukan yang menggunakan refleksi untuk beralih ke properti yang menghasilkan kesalahan yang tidak Anda antisipasi pada waktu desain.

Saya mengatakan secara umum karena mungkin ada saat-saat ketika Anda benar-benar ingin memblokir sesuatu tanpa terlalu khawatir tentang konsekuensinya. Keamanan Saya kira akan menjadi kasus klasik di sana.

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.