Saya baru saja meninjau beberapa kode yang saya tulis beberapa waktu lalu, dan dapat melihat bahwa saya memiliki beberapa metode pribadi yang melempar argumentnullexceptions dan / atau argumentexions jika ada masalah dengan parameter metode.
Saya kira alasan saya adalah membantu aplikasi bukti di masa depan jika seseorang mencoba untuk "menyalahgunakan" metode di masa depan. Namun, mengingat ini adalah metode pribadi dan orang-orang yang cenderung memanggil metode ini dapat melihat komentar dan kode yang terkait, tidak perlu membuang ini. Jelas tidak ada salahnya memilikinya, meskipun itu menambah kekacauan.
Perasaan saya adalah bahwa pengecualian ini umumnya lebih bermanfaat pada sesuatu seperti API yang akan diekspos secara publik.
sumber
Seperti semua yang lain itu tergantung ....
Jika metode publik adalah pembungkus sederhana yang memanggil metode pribadi (di sepanjang garis metode kelebihan beban pribadi) maka mungkin masuk akal untuk melemparkan pengecualian dalam metode pribadi alih-alih memeriksa di masing-masing metode publik.
Secara umum jika tidak memenuhi definisi di atas maka saya biasanya tidak akan memeriksa argumen / melemparkan pengecualian pada metode pribadi. Meskipun ada kasus lain saya biasanya melakukan ini dalam metode pribadi sebelum melakukan beberapa operasi mahal yang bisa gagal sebagian jika argumen tidak valid.
sumber
Saya menyadari bahwa sementara pertanyaan tidak memiliki tag bahasa, itu mungkin secara implisit berbicara tentang "bahasa kopi". Tapi hanya demi kelengkapan, saya ingin menyebutkan konsensus yang agak menyimpang di dunia C ++.
Ada tiga hal yang biasanya diminati oleh programmer C ++:
noexcept
?Di masa lalu, saya telah mendekati masalah pertama dengan menulis kode seperti ini
mana
CHECK_ARGS
yang#define
d ke waktu kompilasi konstan sehingga compiler dapat sepenuhnya menghilangkan semua argumen kode pengecekan di dioptimalkan membangun. (Saya tidak mengatakan bahwa mengkompilasi cek adalah hal yang baik secara umum, tetapi saya percaya bahwa pengguna harus memiliki opsi untuk mengkompilasinya.)Saya masih suka tentang solusi ini bahwa kode pemeriksaan argumen terlihat jelas dikelompokkan bersama ke dalam
if
. Namun, masalah kedua dan ketiga tidak terpecahkan dengan ini. Oleh karena itu, saya sekarang lebih condong ke arah menggunakanassert
makro untuk memeriksa argumen.Standar pengkodean Boost setuju dengan ini:
Ada ceramah yang sangat menarik yang diberikan oleh John Lakos di CppCon'14 berjudul Defensive Programming Done Right ( bagian 1 , bagian 2 ). Pada bagian pertama ceramahnya, ia membahas teori kontrak dan perilaku yang tidak terdefinisi. Pada bagian kedua, dia menyajikan apa yang saya anggap proposal yang sangat bagus untuk pemeriksaan argumen sistematis. Pada dasarnya, ia mengusulkan makro pernyataan yang memungkinkan pengguna untuk memilih berapa banyak anggaran (dalam hal penggunaan CPU) dia bersedia menyumbang ke perpustakaan untuk memeriksa argumen dan membuat perpustakaan bijaksana menggunakan anggaran itu. Sebagai tambahan, pengguna juga dapat menginstal fungsi penanganan kesalahan global yang akan dipanggil jika kontrak yang rusak terdeteksi.
Mengenai aspek bahwa suatu fungsi bersifat pribadi, saya tidak berpikir bahwa ini berarti kita seharusnya tidak pernah memeriksa argumennya. Kita mungkin lebih mempercayai kode kita sendiri untuk tidak melanggar kontrak fungsi internal tetapi kita juga tahu bahwa kita juga tidak sempurna. Mengecek argumen dalam fungsi internal sama membantu dalam mendeteksi bug kita sendiri seperti halnya dalam fungsi publik untuk mendeteksi bug dalam kode klien.
sumber
Pertimbangkan struktur berikut:
Logika internal: Fungsi ini diasumsikan dipanggil dengan parameter yang benar dan karenanya menggunakan penegasan untuk memverifikasi prasyarat, persyaratan akhir, dan invarian untuk memeriksa logika bagian dalam Anda.
Antarmuka pengguna wrapper: Fungsi ini membungkus fungsi internal dan menggunakan InvalidArgumentExceptions untuk menangani nilai-nilai yang salah dan untuk memberitahu pengguna untuk memperbaiki input nya:
Assert(x).hasLength(4);
,Assume(y).isAlphanumeric();
,Assert(z).isZipCode();
,Assume(mailAdress).matchesRegex(regex_MailAdress);
,Reject(x).ifEmpty();
, dllBatch interface wrapper: Fungsi ini membungkus fungsi internal dan menggunakan logging, tanda validitas dan statistik untuk menangani nilai yang salah tanpa mengganggu beberapa tugas yang sudah berjalan lama. Penandaan tersebut dapat digunakan kemudian oleh seseorang yang memeriksa dan membersihkan database hasil.
Pembungkus antarmuka baris perintah: fungsi ini membungkus fungsi internal dan meminta lagi input terakhir.
Anda harus menggunakan keduanya - menegaskan dan pengecualian - dalam metode yang berbeda untuk tugas yang berbeda. Anda harus memisahkan logika internal dari pengecekan parameter. Bandingkan dengan pemisahan Model, View, Controller.
sumber
Ada cara yang lebih baik untuk menghindari cek referensi nol: gunakan kontrak kode atau kerangka kerja AOP untuk melakukan pemeriksaan untuk Anda. Google "c # code contract" atau "postsharp".
sumber