Saya menemukan halaman MSDN ini yang menyatakan:
Jangan melempar Exception , SystemException , NullReferenceException , atau IndexOutOfRangeException dengan sengaja dari kode sumber Anda sendiri.
Sayangnya, tidak repot-repot menjelaskan alasannya. Saya bisa menebak alasannya tetapi saya berharap seseorang yang lebih berwibawa pada subjek dapat menawarkan wawasan mereka.
Dua yang pertama masuk akal, tetapi dua yang terakhir tampak seperti yang ingin Anda gunakan (dan sebenarnya, saya punya).
Selanjutnya, apakah ini satu-satunya pengecualian yang harus dihindari? Jika ada yang lain, apakah mereka dan mengapa mereka juga harus dihindari?
c#
exception-handling
DonBoitnott
sumber
sumber
NullArgumentException
beberapa orang yang mungkin membingungkan keduanya.ApplicationException
Jawaban:
Exception
adalah tipe dasar untuk semua pengecualian, dan karenanya sangat tidak spesifik. Anda tidak boleh membuang pengecualian ini karena tidak mengandung informasi yang berguna. Penangkapan kode panggilan untuk pengecualian tidak dapat menghilangkan ambiguitas pengecualian yang sengaja dilemparkan (dari logika Anda) dari pengecualian sistem lain yang sama sekali tidak diinginkan dan menunjukkan kesalahan nyata.Alasan yang sama juga berlaku untuk
SystemException
. Jika Anda melihat daftar jenis turunan, Anda dapat melihat sejumlah besar pengecualian lain dengan semantik yang sangat berbeda.NullReferenceException
danIndexOutOfRangeException
dari jenis yang berbeda. Sekarang ini adalah pengecualian yang sangat spesifik, jadi membuangnya bisa saja tidak masalah. Namun, Anda tetap tidak ingin membuang ini, karena biasanya itu berarti ada beberapa kesalahan aktual dalam logika Anda. Misalnya pengecualian referensi null berarti Anda mencoba mengakses anggota objek yangnull
. Jika itu adalah kemungkinan dalam kode Anda, Anda harus selalu memeriksa secara eksplisitnull
dan melemparkan pengecualian yang lebih berguna sebagai gantinya (misalnyaArgumentNullException
). Demikian pula,IndexOutOfRangeException
s terjadi ketika Anda mengakses indeks yang tidak valid (pada array — bukan daftar). Anda harus selalu memastikan bahwa Anda tidak melakukan itu di tempat pertama dan memeriksa batas-batas misalnya array terlebih dahulu.Ada beberapa pengecualian lain seperti keduanya, misalnya
InvalidCastException
atauDivideByZeroException
, yang diberikan untuk kesalahan tertentu dalam kode Anda dan biasanya berarti Anda melakukan sesuatu yang salah atau Anda tidak memeriksa beberapa nilai yang tidak valid terlebih dahulu. Dengan membuangnya secara sadar dari kode Anda, Anda hanya mempersulit kode pemanggil untuk menentukan apakah mereka terlempar karena beberapa kesalahan dalam kode, atau hanya karena Anda memutuskan untuk menggunakannya kembali untuk sesuatu dalam implementasi Anda.Tentu saja, ada beberapa pengecualian (hah) untuk aturan ini. Jika Anda sedang membangun sesuatu yang dapat menyebabkan pengecualian yang sama persis dengan yang sudah ada, silakan gunakan itu, terutama jika Anda mencoba untuk mencocokkan beberapa perilaku bawaan. Pastikan Anda memilih jenis pengecualian yang sangat spesifik.
Namun secara umum, kecuali Anda menemukan pengecualian (spesifik) yang memenuhi kebutuhan Anda, Anda harus selalu mempertimbangkan untuk membuat jenis pengecualian Anda sendiri untuk pengecualian khusus yang diharapkan. Terutama saat Anda menulis kode perpustakaan, ini bisa sangat berguna untuk memisahkan sumber pengecualian.
sumber
IList
implementasi, Anda tidak dapat mempengaruhi indeks yang diminta, itu kesalahan logika pemanggil ketika indeks tidak valid, dan Anda hanya dapat memberi tahu mereka kesalahan logika ini dengan memberikan pengecualian yang sesuai. MengapaIndexOutOfRangeException
tidak sesuai?IList
, maka Anda akan membuang aArgumentOutOfRangeException
seperti yang disarankan oleh dokumentasi antarmuka .IndexOutOfRangeException
adalah untuk array, dan sejauh yang saya tahu, Anda tidak dapat mengimplementasikan ulang array.NullReferenceException
biasanya secara internal dilemparkan sebagai kasus khusus dari sebuahAccessViolationException
(IIRC pengujiannya adalah seperticmp [addr], addr
, yaitu mencoba untuk mendereferensi penunjuk dan jika gagal dengan pelanggaran akses, menangani perbedaan antara NRE dan AVE dalam penanganan interupsi yang dihasilkan). Jadi selain alasan semantik, ada juga beberapa kecurangan yang terlibat. Ini juga dapat membantu mencegah Anda memeriksanull
secara manual ketika tidak membantu - jika Anda tetap akan membuang NRE, mengapa tidak membiarkan .NET melakukannya?Saya menduga maksud dengan 2 terakhir adalah untuk mencegah kebingungan dengan pengecualian bawaan yang memiliki arti yang diharapkan. Namun, saya berpendapat bahwa jika Anda mempertahankan maksud pengecualian yang tepat : itu adalah yang benar untuk
throw
. Misalnya, jika Anda menulis koleksi ubahsuaian, tampaknya sepenuhnya masuk akal untuk digunakanIndexOutOfRangeException
- lebih jelas dan lebih spesifik, IMO, daripadaArgumentOutOfRangeException
. Dan sementaraList<T>
mungkin memilih yang terakhir, setidaknya ada 41 tempat (milik reflektor) di BCL (tidak termasuk array) yang melempar dipesan lebih dahuluIndexOutOfRangeException
- tidak ada yang cukup "tingkat rendah" untuk pantas mendapatkan pengecualian khusus. Jadi ya, saya pikir Anda bisa dengan adil membantah bahwa pedoman itu konyol. Juga,NullReferenceException
agak berguna dalam metode ekstensi - jika Anda ingin mempertahankan semantik yang:melempar
NullReferenceException
ketikaobj
adalahnull
.sumber
SomeMethod()
tidak perlu melakukan akses anggota, tidak benar jika memaksanya. Demikian juga: ambil poin itu dengan 41 tempat di BCL yang membuat kustomIndexOutOfRangeException
, dan 16 tempat yang membuat kustomNullReferenceException
ArgumentNullException
alih - alihNullReferenceException
. Meskipun gula sintaksis dari metode ekstensi memungkinkan sintaks yang sama seperti akses anggota normal, itu masih berfungsi dengan sangat berbeda. Dan mendapatkan NRE dariMyStaticHelpers.SomeMethod(obj)
adalah salah.Seperti yang Anda tunjukkan, dalam artikel Membuat dan Melempar Pengecualian (Panduan Pemrograman C #) di bawah topik Hal-hal yang Harus Dihindari Saat Melempar Pengecualian , Microsoft memang mencantumkan
System.IndexOutOfRangeException
sebagai jenis pengecualian yang tidak boleh dibuang dengan sengaja dari kode sumber Anda sendiri.Sebaliknya, bagaimanapun, dalam lemparan artikel (C # Reference) , Microsoft tampaknya melanggar pedomannya sendiri. Berikut adalah metode yang disertakan Microsoft dalam contohnya:
Jadi, Microsoft sendiri tidak konsisten karena mendemonstrasikan pelemparan
IndexOutOfRangeException
dalam dokumentasinya untukthrow
!Hal ini membuat saya percaya bahwa setidaknya untuk kasus
IndexOutOfRangeException
, mungkin ada saat-saat di mana jenis pengecualian itu dapat dilemparkan oleh programmer dan dianggap sebagai praktik yang dapat diterima.sumber
Ketika saya membaca pertanyaan Anda, saya bertanya pada diri sendiri dalam kondisi apa seseorang ingin membuang tipe pengecualian
NullReferenceException
,InvalidCastException
atauArgumentOutOfRangeException
.Menurut pendapat saya, ketika menemukan salah satu dari jenis pengecualian tersebut, saya (pengembang) merasa prihatin dengan peringatan dalam arti bahwa kompiler sedang berbicara kepada saya. Jadi, mengizinkan Anda (pengembang) untuk melempar tipe pengecualian tersebut sama dengan (kompilator) menjual tanggung jawab. Misalnya, ini menyarankan kompilator sekarang harus mengizinkan pengembang untuk memutuskan apakah suatu objek
null
. Tetapi membuat penentuan seperti itu seharusnya menjadi tugas compiler.PS: Sejak tahun 2003 saya mengembangkan pengecualian saya sendiri sehingga saya bisa membuangnya sesuai keinginan. Saya pikir itu dianggap praktik terbaik untuk melakukannya.
sumber
Mengesampingkan diskusi tentang
NullReferenceException
danIndexOutOfBoundsException
kesampingkan:Bagaimana dengan menangkap dan melempar
System.Exception
. Saya telah banyak membuang jenis pengecualian ini dalam kode saya dan saya tidak pernah mengacaukannya. Demikian pula, sangat sering saya menangkapException
tipe yang tidak spesifik , dan itu juga bekerja dengan cukup baik untuk saya. Jadi kenapa begitu?Biasanya pengguna berpendapat, bahwa mereka harus bisa membedakan penyebab kesalahan. Dari pengalaman saya, hanya ada sedikit situasi di mana Anda ingin menangani jenis pengecualian yang berbeda secara berbeda. Untuk kasus tersebut, saat Anda mengharapkan pengguna menangani error secara terprogram, Anda harus menampilkan jenis pengecualian yang lebih spesifik. Untuk kasus lain, saya tidak yakin dengan pedoman praktik terbaik umum.
Jadi, terkait melempar,
Exception
saya tidak melihat alasan untuk melarang ini dalam semua kasus.EDIT: juga dari halaman MSDN:
Klausa tangkapan yang berlebihan dengan logika individu untuk jenis pengecualian yang berbeda juga bukan praktik terbaik.
sumber