Haruskah saya membuat pengecualian sendiri, atau mengooptasi pengecualian serupa untuk tujuan yang agak non-standar?

8

Ini adalah pertanyaan desain umum, tapi saya fokus pada C # dan .NET karena itu adalah bahasa yang saya gunakan saat ini.

Haruskah saya membuat sendiri, kelas pengecualian baru, atau mengkooptasi kerangka kerja yang ada untuk tujuan yang sedikit berbeda?

Sebagai contoh, saya mendapati diri saya membutuhkan pengecualian yang menunjukkan anggota (yaitu, dari jenis misalnya) diharapkan, tetapi belum ditemukan saat membaca perakitan menggunakan Mono.Cecil. Pustaka kelas dasar mendefinisikan pengecualian MissingMemberException, yang tampaknya berkomunikasi persis apa yang saya inginkan, tetapi deskripsi mengatakan:

Pengecualian yang dilemparkan ketika ada upaya untuk secara dinamis mengakses anggota kelas yang tidak ada.

Yang tidak pas, karena saya tidak secara dinamis mengakses anggota, tetapi bekerja dengan majelis secara pasif.

GregRos
sumber
Yang Anda inginkan adalah menggunakan kembali nama tetapi bukan tipe. Ada makna khusus yang melekat pada MissingMemberException. Cukup tentukan jenis baru yang khusus untuk kerangka kerja Anda dan membawa makna yang tepat.
usr

Jawaban:

7

Secara umum

Pengecualian subklasifikasi adalah ide yang bagus untuk mengelompokkan pengecualian ke dalam keluarga atau pengelompokan yang mereka ikuti. Ini juga memungkinkan kode klien kesempatan untuk menangani pengecualian berdasarkan kesalahan spesifik atau lebih umum. Saya biasanya membagi pohon di suatu tempat dekat root antara kesalahan logis dan runtime (misalnya dalam C ++ the std::runtime_errorvs. std::logic_error).

Mampu membedakan antara pengecualian sistem dan pengecualian aplikasi Anda juga merupakan ide yang bagus. Akan aneh jika kode klien mengawasi kegagalan sistem dari beberapa jenis tetapi menangkap kesalahan logis kode Anda (melalui kelas dasar).

Mengingat kasus ini dan C #

C # memiliki hierarki pengecualian yang kaya dan besar - Saya tidak akan mencoba mengambil kelas dasar terlalu jauh ke dalamnya. Mengikuti contoh Anda, sepertinya Anda melempar kesalahan logis (atau setidaknya kesalahan aplikasi), sehingga kelas dasar atau bahkan pengecualian itu akan mengisyaratkan kesalahan sistem. Pengecualian yang tepat dapat diperdebatkan, tetapi saya pikir dalam kasus ini itu bukan pilihan yang baik.

Hirarki

Saya akan membangun hierarki yang memungkinkan Anda untuk membedakan antara kesalahan sistem dan aplikasi dan kemudian lebih jauh antara runtime dan kesalahan logis. Jangan takut untuk menggunakan pengecualian dalam - menangkap kesalahan sistem dan membungkusnya dengan sesuatu yang lebih bermakna mengingat konteks di mana ia dilemparkan. Jangan berlebihan, fokuslah pada apa yang akan menjadi pengecualian utama. Pengecualian dapat memiliki deskripsi tekstual unik yang terkait dengannya - menggunakannya untuk memberikan pengguna lebih banyak detail atau petunjuk tentang apa yang harus dilakukan untuk memperbaiki masalah.

Niall
sumber
2
Ini adalah strategi yang brilian ketika mensubklasifikasikan pengecualian. Saya tidak yakin apakah Anda mengatakan untuk pengecualian subclass dalam setiap kasus atau Anda hanya mengatakan bahwa ketika Anda subkelas ini adalah bagaimana Anda harus melakukannya. Sehubungan dengan apakah Anda harus subkelas saya setuju dengan jawaban @aniel yang diposting.
Chuck Conway
3

Jawabannya tentu saja "itu tergantung," tetapi mengingat kasus penggunaan Anda, saya akan mengatakan tidak. Inilah alasannya:

C # adalah bahasa yang luar biasa - goresan itu, yang terbaik - berorientasi objek. Sangat bagus, pada kenyataannya, bahwa saya kadang-kadang akan terjebak mencoba menerapkan visi fanatik murni tentang apa yang dimulai sebagai proyek sederhana. Itu tidak banyak terjadi pada saya ketika menulis JavaScript atau Objective-C atau kode PHP.

Ketika saya berada dalam "mode" ini, kelumpuhan semacam ini, salah satu gejala dapat menjadi obsesi dengan penanganan pengecualian dan obat generik serta meta-pemrograman. Terkadang ketiganya bersama. Jauh lebih mungkin menjadi masalah ketika saya mengerjakan sesuatu yang baru, relatif tidak dikenal, atau dengan spesifikasi dan tujuan yang jelek. Alih-alih menyibukkan diri dalam detail implementasi , saya pikir, mengapa mencoba membuat sesuatu yang dapat mengakomodasi sebagian besar skenario yang saya antisipasi secara wajar? Kemudian, ketika saya mencari tahu detailnya, fondasi akan diletakkan dan saya akan menulis banyak metode kecil yang gemuk, dan seterusnya. Mungkin orang lain akan bekerja pada kode UI, saya hanya akan memberi mereka layanan yang bagus dan kontrak ini ...

Sayangnya, itu belum terjadi pada saya. Yang cenderung terjadi adalah saya memulai jalur ini dengan mengerjakan "infrastruktur" - hal-hal seperti:

  • Menulis antarmuka wadah IoC saya sendiri atau bermain-main dengan Castle.Windsor
  • Menentukan bagaimana saya akan menangani pemetaan tipe dalam aplikasi
  • Menulis logika aliran kontrol untuk kelas dasar abstrak yang menyerupai Interceptors dan membungkus panggilan ke anggota abstrak dengan penanganan pengecualian
  • Membuat kelas dasar abstrak untuk IRepository, IUnitOfWork, IDomainService, ICrossCuttingValidation, dll
  • Mencoba menggambarkan model objek hierarkis untuk sesuatu yang sifatnya menyangkal meta-approach ( sepertiIFrameworkException )

Ketika Anda terpaku pada apakah deskripsi pengecualian cukup tepat untuk selera Anda, Anda benar-benar menolak beberapa fitur penting lainnya untuk diimplementasikan. Sifat pengecualian juga menunjukkan - ini bukan pengecualian yang didorong oleh peristiwa , ternyata jauh dari metodologi input (seperti UI atau pipa atau sesuatu) dan mungkin bersifat deterministik - karena Anda tidak dapat memprediksi apa yang akan dimasukkan oleh pengguna, tetapi Anda dapat memprediksi perakitan mana yang Anda pilih untuk memuat atau yang lainnya.

Omong-omong, jika uraiannya sangat mengganggu Anda, tidak bisakah Anda menulis metode ekstensi untuk menimpanya dalam ruang lingkup yang sesuai?

Jadi ini benar-benar hanya saya yang memproyeksikan abstraksi saya yang berlebihan dan analisis kelumpuhan kepada Anda, tetapi saya pikir itu mungkin tepat. Saya akan mengatakan bahwa untuk tetap di sisi aman, hanya subkelas Exceptionketika:

  • Anda sebenarnya mengalami pengecualian runtime yang ingin Anda tangani secara umum
  • Pengecualian runtime bukan sesuatu yang bisa Anda singkirkan pada waktu desain
  • Pengecualian belum tercakup dengan baik oleh sejumlah besar Exceptionsubclass yang ada
  • Anda sebenarnya memiliki ide dalam pikiran tentang bagaimana Anda ingin menangani pengecualian ATAU jika tidak, hanya karena itu sangat rumit sehingga Anda perlu memikirkannya dan kembali ke sana.
  • Gagasan Anda melampaui mengubah metadata-nya, cakupannya, pengecualian dalamnya, dll, dan lebih banyak berurusan dengan objek atau peristiwa yang mendasari menghasilkan pengecualian dan / atau sarana untuk benar-benar menghadapinya.
  • Anda telah menulis atau tidak bertanggung jawab atas sebagian besar sisi yang berhadapan dengan input seperti UI
tacos_tacos_tacos
sumber
Saya menghargai pendekatan pragmatis Anda. Seperti halnya semua itu tergantung.
Chuck Conway
1

Dalam pandangan saya pengecualian khusus hanya masuk akal dalam 2 kasus:

1) Anda sedang mengembangkan Api

2) Anda menggunakannya dalam kode Anda untuk pulih dari kegagalan.

Dalam skenario lain apa pun, pengecualian bawaan harus memadai.

Dalam kasus Anda, Anda dapat menggunakan InvalidArgumentException

Daniel
sumber
Anda harus sedikit memperluas jawaban Anda dan memberikan "Mengapa" untuk setiap poin-poin. Anda tepat di sini. Membuat pengecualian khusus adalah sistem / hierarki lain yang harus dipertahankan.
Chuck Conway