Saya sedang melihat artikel C # - Data Transfer Object pada DTO serializable.
Artikel ini termasuk potongan kode ini:
public static string SerializeDTO(DTO dto) {
try {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
catch(Exception ex) {
throw ex;
}
}
Sisa artikel ini terlihat waras dan masuk akal (untuk noob), tapi coba-coba-lempar melempar WtfException ... Bukankah ini sama dengan tidak menangani pengecualian sama sekali?
Jadi:
public static string SerializeDTO(DTO dto) {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
Atau apakah saya melewatkan sesuatu yang mendasar tentang penanganan kesalahan di C #? Ini hampir sama dengan Java (minus pengecualian yang diperiksa), bukan? ... Yaitu, mereka berdua menyempurnakan C ++.
Pertanyaan Stack Overflow Perbedaan antara melempar kembali parameter-less catch dan tidak melakukan apa-apa? tampaknya mendukung pendapat saya bahwa try-catch-throw adalah-no-op.
EDIT:
Hanya untuk meringkas bagi siapa saja yang menemukan utas ini di masa depan ...
TIDAK
try {
// Do stuff that might throw an exception
}
catch (Exception e) {
throw e; // This destroys the strack trace information!
}
Informasi jejak tumpukan dapat menjadi sangat penting untuk mengidentifikasi akar penyebab masalah!
MELAKUKAN
try {
// Do stuff that might throw an exception
}
catch (SqlException e) {
// Log it
if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
// Do special cleanup, like maybe closing the "dirty" database connection.
throw; // This preserves the stack trace
}
}
catch (IOException e) {
// Log it
throw;
}
catch (Exception e) {
// Log it
throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
// Normal clean goes here (like closing open files).
}
Tangkap pengecualian yang lebih spesifik sebelum yang kurang spesifik (seperti Java).
Referensi:
sumber
Jawaban:
Pertama; cara kode dalam artikel itu melakukannya adalah jahat.
throw ex
akan mengatur ulang tumpukan panggilan dalam pengecualian ke titik di mana pernyataan melempar ini adalah; kehilangan informasi tentang di mana pengecualian sebenarnya dibuat.Kedua, jika Anda hanya menangkap dan melempar kembali seperti itu, saya tidak melihat nilai tambah, contoh kode di atas akan sama baiknya (atau, mengingat
throw ex
bitnya, bahkan lebih baik) tanpa try-catch.Namun, ada beberapa kasus di mana Anda mungkin ingin menangkap dan memikirkan kembali pengecualian. Penebangan bisa menjadi salah satunya:
sumber
ex
objek itu, maka tidak perlu untuk instantiate.throw ex
tidak me-restart stacktrace.Jangan lakukan ini,
Anda akan kehilangan informasi jejak tumpukan ...
Baik lakukan,
ATAU
Salah satu alasan Anda mungkin ingin melakukan rethrow adalah jika Anda menangani pengecualian yang berbeda, misalnya
sumber
C # (sebelum C # 6) tidak mendukung CIL "pengecualian yang difilter", yang dilakukan VB, jadi di C # 1-5 satu alasan untuk melempar kembali pengecualian adalah karena Anda tidak memiliki informasi yang cukup pada saat penangkapan () untuk menentukan apakah Anda ingin menangkap pengecualian.
Misalnya, di VB bisa Anda lakukan
... yang tidak akan menangani MyExceptions dengan nilai ErrorCode yang berbeda. Di C # sebelum v6, Anda harus menangkap dan melempar kembali MyException jika ErrorCode bukan 123:
Karena C # 6.0 Anda dapat memfilter seperti halnya dengan VB:
sumber
Alasan utama saya memiliki kode seperti:
Jadi saya dapat memiliki breakpoint di tangkapan, yang memiliki objek pengecualian yang dipakai. Saya melakukan ini banyak saat mengembangkan / debugging. Tentu saja, kompiler memberi saya peringatan pada semua e yang tidak digunakan, dan idealnya mereka harus dihapus sebelum rilis rilis.
Mereka bagus selama debugging.
sumber
#if DEBUG
sekitar KEDUAtry {
dan} catch () {...}
agak berantakan dan, terus terang, membuat saya mual ... Pra-prosesor, secara umum, bukan teman saya.Alasan yang sah untuk mengkaji ulang pengecualian dapat karena Anda ingin menambahkan informasi ke pengecualian, atau mungkin membungkus pengecualian asli dalam salah satu buatan Anda sendiri:
sumber
Tidak persis sama, itu tidak sama. Ini mengatur ulang stacktrace pengecualian. Meskipun saya setuju bahwa ini mungkin kesalahan, dan dengan demikian contoh kode yang buruk.
sumber
Anda tidak ingin membuang mantan - karena ini akan kehilangan tumpukan panggilan. Lihat Penanganan Pengecualian (MSDN).
Dan ya, coba ... tangkapan tidak melakukan hal yang berguna (selain kehilangan tumpukan panggilan - jadi sebenarnya lebih buruk - kecuali karena alasan tertentu Anda tidak ingin membuka informasi ini).
sumber
Suatu hal yang belum disebutkan orang adalah bahwa sementara .NET bahasa tidak benar-benar membuat perbedaan yang tepat, pertanyaan apakah seseorang harus mengambil tindakan ketika pengecualian terjadi, dan apakah seseorang akan menyelesaikannya , sebenarnya adalah pertanyaan yang berbeda. Ada banyak kasus di mana seseorang harus mengambil tindakan berdasarkan pengecualian yang tidak memiliki harapan untuk diselesaikan, dan ada beberapa kasus di mana semua yang diperlukan untuk "menyelesaikan" pengecualian adalah untuk melepaskan tumpukan ke titik tertentu - tidak diperlukan tindakan lebih lanjut .
Karena kebijaksanaan umum bahwa seseorang seharusnya hanya "menangkap" hal-hal yang dapat "ditangani", banyak kode yang harus mengambil tindakan ketika pengecualian terjadi, tidak. Misalnya, banyak kode akan memperoleh kunci, menempatkan objek yang dijaga "sementara" ke dalam keadaan yang melanggar invariannya, kemudian meletakkannya objek ke keadaan yang sah, dan kemudian melepaskan kunci kembali sebelum orang lain dapat melihat objek. Jika pengecualian terjadi ketika objek dalam keadaan berbahaya-tidak valid, praktik umum adalah melepaskan kunci dengan objek masih dalam keadaan itu. Pola yang jauh lebih baik adalah memiliki pengecualian yang terjadi saat objek berada dalam kondisi "berbahaya" yang secara tegas membatalkan kunci sehingga setiap upaya di masa depan untuk mendapatkannya akan segera gagal.
Dalam sebagian besar bahasa .NET, satu-satunya cara kode mengambil tindakan berdasarkan pengecualian adalah dengan
catch
melakukannya (meskipun ia tahu itu tidak akan menyelesaikan pengecualian), lakukan tindakan yang dimaksud dan kemudian kembalithrow
). Pendekatan lain yang mungkin jika kode tidak peduli tentang pengecualian apa yang dilemparkan adalah menggunakanok
bendera dengantry/finally
blok; aturok
benderafalse
sebelum blok, dantrue
sebelum blok keluar, dan sebelum apa punreturn
yang ada di dalam blok. Kemudian, di dalamfinally
, asumsikan bahwa jikaok
tidak disetel, pengecualian harus terjadi. Pendekatan semacam itu secara semantik lebih baik daripadacatch
/throw
, tetapi jelek dan kurang bisa dipertahankan.sumber
Ini bisa berguna ketika fungsi pemrograman Anda untuk perpustakaan atau dll.
Struktur rethrow ini dapat digunakan untuk mengatur ulang tumpukan panggilan dengan sengaja sehingga alih-alih melihat pengecualian yang dilemparkan dari fungsi individual di dalam fungsi, Anda mendapatkan pengecualian dari fungsi itu sendiri.
Saya pikir ini hanya digunakan sehingga pengecualian yang dilemparkan lebih bersih dan tidak masuk ke "akar" perpustakaan.
sumber
Salah satu alasan yang memungkinkan untuk melakukan throw-throw adalah untuk menonaktifkan filter pengecualian yang lebih dalam dari stack agar tidak difilter ( tautan lama acak ). Tapi tentu saja, jika itu niatnya, akan ada komentar di sana yang mengatakannya.
sumber
Itu tergantung apa yang Anda lakukan di blok tangkap, dan jika Anda ingin meneruskan kesalahan ke kode panggilan atau tidak.
Anda mungkin mengatakan
Catch io.FileNotFoundExeption ex
dan kemudian menggunakan jalur file alternatif atau semacamnya, tetapi masih melempar kesalahan.Juga melakukan
Throw
alih - alihThrow Ex
memungkinkan Anda menyimpan jejak tumpukan penuh. Throw ex me-restart jejak stack dari pernyataan throw (saya harap itu masuk akal).sumber
Sementara banyak dari jawaban lain memberikan contoh yang bagus tentang mengapa Anda mungkin ingin menangkap kembali perkecualian, tidak ada yang tampaknya menyebutkan skenario 'akhirnya'.
Contoh dari ini adalah di mana Anda memiliki metode di mana Anda mengatur kursor (misalnya ke kursor tunggu), metode ini memiliki beberapa titik keluar (misalnya jika () kembali;) dan Anda ingin memastikan kursor diatur ulang di akhir metode.
Untuk melakukan ini, Anda dapat membungkus semua kode dengan mencoba / menangkap / akhirnya. Pada akhirnya atur kursor kembali ke kursor kanan. Agar Anda tidak mengubur pengecualian yang valid, kembalikan di tangkapan.
sumber
catch
merupakan bagian wajib daritry...finally
sejarah, atau apakah itu memainkan peran fungsional dalam contoh ini? - Saya baru saja memeriksa ulang, dan saya dapat menggunakantry {} finally {}
tanpa catch catch block sama sekali.Pada contoh dalam kode yang Anda posting ada, pada kenyataannya, tidak ada gunanya menangkap pengecualian karena tidak ada yang dilakukan pada tangkapan itu hanya ulang-ulang, pada kenyataannya itu lebih berbahaya daripada baiknya sebagai tumpukan panggilan hilang .
Namun, Anda akan mendapatkan pengecualian untuk melakukan beberapa logika (misalnya menutup koneksi sql dari kunci file, atau hanya beberapa logging) dalam hal pengecualian melemparkannya kembali ke kode panggilan untuk menangani. Ini akan lebih umum di lapisan bisnis daripada kode ujung depan karena Anda mungkin ingin pembuat kode mengimplementasikan lapisan bisnis Anda untuk menangani pengecualian.
Untuk mengulangi kembali meskipun TIDAK ada gunanya menangkap pengecualian pada contoh yang Anda posting. JANGAN lakukan seperti itu!
sumber
Maaf, tetapi banyak contoh sebagai "desain yang ditingkatkan" masih berbau mengerikan atau bisa sangat menyesatkan. Telah mencoba {} catch {log; melempar} sama sekali tidak ada gunanya. Pencatatan pengecualian harus dilakukan di tempat sentral di dalam aplikasi. Pengecualian memunculkan stacktrace, mengapa tidak mencatatnya di suatu tempat dan dekat dengan perbatasan sistem?
Perhatian harus digunakan ketika Anda membuat serial konteks Anda (yaitu DTO dalam satu contoh yang diberikan) hanya ke dalam pesan log. Ini dapat dengan mudah berisi informasi sensitif yang mungkin tidak ingin menjangkau semua orang yang dapat mengakses file log. Dan jika Anda tidak menambahkan informasi baru ke pengecualian, saya benar-benar tidak melihat titik pembungkus pengecualian. Java tua yang baik memiliki beberapa poin untuk itu, itu membutuhkan penelepon untuk mengetahui pengecualian apa yang harus diharapkan seseorang kemudian memanggil kode. Karena Anda tidak memiliki ini dalam. NET, pembungkus tidak ada gunanya pada setidaknya 80% dari kasus yang saya lihat.
sumber
Selain apa yang dikatakan orang lain, lihat jawaban saya untuk pertanyaan terkait yang menunjukkan bahwa penangkapan dan pemindahan kembali bukan larangan (ada dalam VB, tetapi beberapa kode bisa C # dipanggil dari VB).
sumber
Sebagian besar jawaban berbicara tentang skenario catch-log-rethrow.
Alih-alih menuliskannya dalam kode Anda, pertimbangkan untuk menggunakan AOP, khususnya Postsharp.Diagnostic.Toolkit dengan OnExceptionOptions, SertakanParameterValue dan Sertakan Dokumen Ini
sumber
Rethrowing exception via
throw
berguna ketika Anda tidak memiliki kode tertentu untuk menangani pengecualian saat ini, atau dalam kasus ketika Anda memiliki logika untuk menangani kasus kesalahan tertentu tetapi ingin melewatkan semua yang lain.Contoh:
Namun, ada juga cara lain untuk melakukan ini, menggunakan klausa kondisional di blok tangkap:
sumber