Apa praktik terbaik yang harus dipertimbangkan ketika menangkap pengecualian dan melemparkannya kembali? Saya ingin memastikan bahwa jejak Exception
objek InnerException
dan tumpukan dipertahankan. Apakah ada perbedaan antara blok kode berikut dalam cara mereka menangani ini?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Vs:
try
{
//some code
}
catch
{
throw;
}
sumber
ExceptionDispatchInfo.Capture(ex).Throw(); throw;
di .NET +4.5 stackoverflow.com/questions/57383/…Jika Anda melempar pengecualian baru dengan pengecualian awal, Anda juga akan mempertahankan jejak tumpukan awal ..
sumber
AggregateException
seharusnya hanya digunakan untuk pengecualian atas operasi agregat. Misalnya, itu dilemparkan olehParallelEnumerable
danTask
kelas-kelas CLR. Penggunaan mungkin harus mengikuti contoh ini.Sebenarnya, ada beberapa situasi dimana
throw
statment tidak akan menyimpan informasi StackTrace. Misalnya, dalam kode di bawah ini:StackTrace akan menunjukkan bahwa baris 54 menaikkan pengecualian, meskipun itu dinaikkan pada baris 47.
Dalam situasi seperti yang dijelaskan di atas, ada dua opsi untuk preseve StackTrace asli:
Memanggil Exception.InternalPreserveStackTrace
Karena ini adalah metode pribadi, itu harus dipanggil dengan menggunakan refleksi:
Saya memiliki kelemahan mengandalkan metode pribadi untuk menjaga informasi StackTrace. Itu bisa diubah di versi .NET Framework. Contoh kode di atas dan solusi yang diusulkan di bawah ini diambil dari weblog Fabrice MARGUERIE .
Memanggil Exception.SetObjectData
Teknik di bawah ini disarankan oleh Anton Tykhyy sebagai jawaban untuk In C #, bagaimana saya bisa memikirkan kembali InnerException tanpa kehilangan pertanyaan susunan jejak .
Meskipun, memiliki keuntungan mengandalkan metode publik hanya itu juga tergantung pada konstruktor pengecualian berikut (yang beberapa pengecualian yang dikembangkan oleh pihak ke-3 tidak diterapkan):
Dalam situasi saya, saya harus memilih pendekatan pertama, karena pengecualian yang diajukan oleh perpustakaan pihak ketiga yang saya gunakan tidak menerapkan konstruktor ini.
sumber
Saat Anda
throw ex
, Anda pada dasarnya melempar pengecualian baru, dan akan kehilangan informasi tumpukan jejak yang asli.throw
adalah metode yang disukai.sumber
Aturan praktisnya adalah untuk menghindari Catching and Throwing the basic
Exception
object. Ini memaksa Anda untuk menjadi sedikit lebih pintar tentang pengecualian; dengan kata lain Anda harus memiliki tangkapan eksplisit untukSqlException
kode penanganan Anda sehingga tidak melakukan sesuatu yang salah dengan aNullReferenceException
.Namun di dunia nyata, menangkap dan mencatat pengecualian basis juga merupakan praktik yang baik, tetapi jangan lupa untuk melakukan semuanya untuk mendapatkan apa
InnerExceptions
yang mungkin ada.sumber
Anda harus selalu menggunakan "lemparan;" untuk memikirkan kembali pengecualian di .NET,
Lihat ini, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
Pada dasarnya MSIL (CIL) memiliki dua instruksi - "melempar" dan "rethrow":
Pada dasarnya saya dapat melihat alasan mengapa "throw ex" menimpa jejak stack.
sumber
throw ex;
akan memikirkan kembali - di Jawa, ya! Tetapi Anda harus menyertakan informasi itu di sini untuk mendapatkan jawaban Grade A. (Meskipun saya masih mengejarExceptionDispatchInfo.Capture
jawaban dari jeuoekdcwzfwccu .)Tidak ada yang menjelaskan perbedaan antara
ExceptionDispatchInfo.Capture( ex ).Throw()
dan dataranthrow
, jadi ini dia. Namun, beberapa orang telah memperhatikan masalah tersebutthrow
.Cara lengkap untuk mengubah kembali pengecualian yang tertangkap adalah menggunakan
ExceptionDispatchInfo.Capture( ex ).Throw()
(hanya tersedia dari .Net 4.5).Di bawah ini ada kasus yang diperlukan untuk menguji ini:
1.
2.
3.
4.
Kasus 1 dan kasus 2 akan memberi Anda jejak tumpukan di mana nomor baris kode sumber untuk
CallingMethod
metode ini adalah nomor baris darithrow new Exception( "TEST" )
baris tersebut.Namun, kasus 3 akan memberi Anda jejak tumpukan di mana nomor baris kode sumber untuk
CallingMethod
metode ini adalah nomor baristhrow
panggilan. Ini berarti bahwa jikathrow new Exception( "TEST" )
garis dikelilingi oleh operasi lain, Anda tidak tahu di mana nomor garis pengecualian itu sebenarnya dilemparkan.Kasus 4 mirip dengan kasus 2 karena nomor baris pengecualian asli dipertahankan, tetapi bukan rethrow nyata karena mengubah jenis pengecualian asli.
sumber
throw ex;
dan ini adalah jawaban terbaik dari semuanya.Beberapa orang benar-benar melewatkan poin yang sangat penting - 'melempar' dan 'melempar mantan' mungkin melakukan hal yang sama tetapi mereka tidak memberi Anda sepotong penting informasi yang merupakan garis di mana pengecualian terjadi.
Pertimbangkan kode berikut:
Ketika Anda melakukan 'melempar' atau 'melempar mantan' Anda mendapatkan jejak tumpukan tetapi baris # akan menjadi # 22 sehingga Anda tidak dapat mengetahui baris mana yang melempar pengecualian secara tepat (kecuali Anda hanya memiliki 1 atau beberapa baris kode di blok coba). Untuk mendapatkan garis yang diharapkan # 17 di pengecualian Anda, Anda harus membuang pengecualian baru dengan jejak tumpukan pengecualian asli.
sumber
Anda juga dapat menggunakan:
Dan setiap pengecualian yang dilemparkan akan menggelembung ke tingkat berikutnya yang menanganinya.
sumber
Saya pasti akan menggunakan:
Itu akan menghemat tumpukan Anda.
sumber
throw
; misalnya Anda bisa membersihkan pakai (di mana Anda HANYA menyebutnya kesalahan) dan kemudian melemparkan pengecualian.FYI Saya baru saja menguji ini dan jejak stack dilaporkan oleh 'throw;' bukan jejak stack yang sepenuhnya benar. Contoh:
Jejak tumpukan menunjuk ke asal pengecualian dengan benar (nomor baris yang dilaporkan) tetapi nomor baris yang dilaporkan untuk foo () adalah garis lemparan; pernyataan, maka Anda tidak bisa mengatakan mana dari panggilan ke bilah () yang menyebabkan pengecualian.
sumber