Cara menggunakan try catch untuk penanganan pengecualian adalah praktik terbaik

201

sembari menjaga kode kolega saya bahkan dari seseorang yang mengaku sebagai pengembang senior, saya sering melihat kode berikut:

try
{
  //do something
}
catch
{
  //Do nothing
}

atau terkadang mereka menulis informasi logging untuk mencatat file seperti try catchblok berikut

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

Saya hanya ingin tahu apakah yang telah mereka lakukan adalah praktik terbaik? Itu membuat saya bingung karena dalam pemikiran saya pengguna harus tahu apa yang terjadi dengan sistem.

Tolong beri saya saran.

Toan Nguyen
sumber
128
Cuplikan # 1 adalah 99,999% dari waktu yang tidak dapat diterima.
leppie
22
Menampilkan pengecualian secara langsung kepada pengguna tidak pernah merupakan ide yang baik terutama karena dua alasan: 1. jika itu adalah pengguna biasa, ia akan merasa terganggu membaca pesan kesalahan yang mengatakan sangat sedikit untuknya. 2. jika dia disebut hacker, dia mungkin mendapatkan informasi yang berguna. Praktik terbaik, IMO, adalah mencatat pengecualian dan menampilkan pesan kesalahan yang bersahabat.
Leri
4
@ leppie Jika sesuatu yang tidak terduga terjadi (seperti NullReferenceatau ArgumentNullyang bukan bagian dari aliran aplikasi) itu berarti ada bug yang perlu diperbaiki sehingga pencatatannya akan membantu untuk men-debug kode Anda lebih cepat.
Leri
14
Menggunakan blok try-catch untuk menyembunyikan pengecualian biasanya merupakan hasil dari pemrograman malas. Ini adalah jalan pintas yang sering digunakan alih-alih menulis kode validasi untuk menguji input. Terkadang ada kalanya pengecualian muncul yang tidak mempengaruhi operasi kode Anda, dan menyembunyikannya seperti ini mungkin OK. Namun ini cukup langka.
Corey
12
@Toan, yah, jika ini adalah pekerjaan batch, saya menangkap di tingkat atas (Utama) untuk login, dan kemudian memikirkan kembali untuk mematikan alarm bahwa pekerjaan diakhiri secara tidak normal. Jika ini adalah aplikasi web, saya membiarkan gelembung pengecualian ke pengendali global, masuk, dan kemudian mengarahkan pengguna ke layar kesalahan. Skenario use case Anda menentukan apa yang Anda lakukan dengan pengecualian itu setelah Anda login atau menanganinya.
Anthony Pegram

Jawaban:

300

Strategi penanganan pengecualian saya adalah:

  • Untuk menangkap semua pengecualian yang tidak ditangani dengan menghubungkannya ke Application.ThreadException event, maka putuskan:

    • Untuk aplikasi UI: untuk mengirimkannya kepada pengguna dengan pesan permintaan maaf (winforms)
    • Untuk Layanan atau aplikasi Konsol: log ke file (layanan atau konsol)

Lalu saya selalu menyertakan setiap bagian kode yang dijalankan secara eksternal di try/catch:

  • Semua peristiwa dipecat oleh infrastruktur Winforms (Memuat, Klik, SelectedChanged ...)
  • Semua acara dipecat oleh komponen pihak ketiga

Lalu saya lampirkan di 'coba / tangkap'

  • Semua operasi yang saya tahu mungkin tidak berfungsi sepanjang waktu (operasi IO, perhitungan dengan potensi nol divisi ...). Dalam kasus seperti itu, saya melempar yang baru ApplicationException("custom message", innerException)untuk melacak apa yang sebenarnya terjadi

Selain itu, saya mencoba yang terbaik untuk mengurutkan pengecualian dengan benar . Ada beberapa pengecualian yang:

  • harus segera ditampilkan kepada pengguna
  • membutuhkan beberapa pemrosesan ekstra untuk menyatukan semua hal ketika hal itu terjadi untuk menghindari masalah kaskade (mis.: menempatkan .EndUpdate di finallybagian saat TreeViewmengisi)
  • pengguna tidak peduli, tetapi penting untuk mengetahui apa yang terjadi. Jadi saya selalu mencatatnya:

    • Dalam log peristiwa
    • atau dalam file .log pada disk

Ini adalah praktik yang baik untuk merancang beberapa metode statis untuk menangani pengecualian dalam penangan kesalahan tingkat atas aplikasi.

Saya juga memaksakan diri untuk mencoba:

  • Ingat SEMUA pengecualian digelembungkan ke tingkat atas . Tidak perlu menempatkan penangan pengecualian di mana-mana.
  • Fungsi-fungsi yang dapat digunakan kembali atau yang dalam tidak perlu menampilkan atau mencatat pengecualian: keduanya digelembungkan secara otomatis atau disusun kembali dengan beberapa pesan khusus di penangan pengecualian saya.

Jadi akhirnya:

Buruk:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Tak berguna:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Berusaha akhirnya tanpa tangkapan sangat valid:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

Apa yang saya lakukan di tingkat atas:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

Apa yang saya lakukan dalam beberapa fungsi yang disebut:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

Ada banyak yang harus dilakukan dengan penanganan pengecualian (Pengecualian Kustom) tetapi aturan yang saya coba ingat cukup untuk aplikasi sederhana yang saya lakukan.

Berikut adalah contoh metode ekstensi untuk menangani pengecualian yang tertangkap dengan cara yang nyaman. Mereka diimplementasikan dengan cara mereka bisa dirantai bersama, dan sangat mudah untuk menambahkan pemrosesan pengecualian Anda sendiri.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}
Larry
sumber
98
catch(Exception ex) { throw ex; }di C # lebih buruk daripada redundan (terlepas dari jenis pengecualian yang Anda tangkap). Untuk rethrow, gunakan throw;. Dengan yang pertama, pengecualian akan terlihat seperti itu berasal dari Anda throw exsedangkan dengan yang terakhir, itu akan benar berasal dari throwpernyataan asli .
CVn
2
Mengapa Anda mengaitkan Application.ThreadExceptionacara dan membungkus setiap pengecualian dengan a catch(Exception ex) {ex.Log(ex);}. Saya mungkin akan setuju bahwa yang pertama adalah praktik yang sangat baik, tetapi yang terakhir menambahkan risiko menduplikasi log kesalahan Anda dan menyembunyikan bahwa pengecualian terjadi. Juga throw exsangat sangat buruk.
Keith
1
Saya mengerti tentang catch (Exception ex) {throw ex; } menjadi tidak berguna. Jadi saya kira "berlebihan" bukanlah kata terbaik untuk menyatakan "Jangan lakukan ini". Itu sebabnya saya mengubah posting sedikit untuk menyatakan lebih baik bahwa dua contoh pertama dari try catch harus dihindari.
Larry
3
Jawaban yang bagus dan konstruktif, yang paling saya nikmati adalah ungkapan Hanya udara :) Dan terima kasih untuk Application.ThreadExceptionacara ini, saya tidak menyadarinya, sangat berguna.
Mahdi Tahsildari
61

Praktik terbaik adalah bahwa penanganan pengecualian tidak boleh menyembunyikan masalah . Ini berarti bahwa try-catchblok harus sangat jarang.

Ada 3 keadaan di mana menggunakan try-catchakal.

  1. Selalu berurusan dengan pengecualian yang dikenal serendah mungkin. Namun, jika Anda mengharapkan pengecualian, biasanya praktik yang lebih baik adalah mengujinya terlebih dahulu. Misalnya parse, pengecualian pemformatan dan aritmatika hampir selalu lebih baik ditangani oleh pemeriksaan logika terlebih dahulu, daripada spesifik try-catch.

  2. Jika Anda perlu melakukan sesuatu dengan pengecualian (misalnya masuk atau memutar kembali suatu transaksi) kemudian lempar kembali pengecualian tersebut.

  3. Selalu berurusan dengan pengecualian yang tidak diketahui setinggi yang Anda bisa - satu - satunya kode yang harus mengkonsumsi pengecualian dan tidak membuangnya haruslah UI atau API publik.

Misalkan Anda terhubung ke API jarak jauh, di sini Anda tahu mengharapkan kesalahan tertentu (dan ada beberapa hal dalam keadaan itu), jadi ini kasus 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Perhatikan bahwa tidak ada pengecualian lain yang ditangkap, karena tidak diharapkan.

Sekarang anggaplah Anda mencoba menyimpan sesuatu ke basis data. Kami harus mengembalikannya jika gagal, jadi kami memiliki case 2:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

Perhatikan bahwa kami melemparkan kembali pengecualian - kode yang lebih tinggi masih perlu mengetahui bahwa ada sesuatu yang gagal.

Akhirnya kami memiliki UI - di sini kami tidak ingin memiliki pengecualian yang tidak ditangani sepenuhnya, tetapi kami juga tidak ingin menyembunyikannya. Di sini kita memiliki contoh kasus 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

Namun, sebagian besar kerangka kerja API atau UI memiliki cara generik untuk melakukan kasus 3. Misalnya ASP.Net memiliki layar kesalahan kuning yang membuang detail pengecualian, tetapi itu dapat diganti dengan pesan yang lebih umum di lingkungan produksi. Mengikuti itu adalah praktik terbaik karena menghemat banyak kode, tetapi juga karena kesalahan logging dan tampilan harus merupakan keputusan konfigurasi daripada hard-coded.

Ini semua berarti bahwa case 1 (pengecualian dikenal) dan case 3 (penanganan UI satu kali) keduanya memiliki pola yang lebih baik (menghindari kesalahan yang diharapkan atau penanganan kesalahan hand off ke UI).

Bahkan case 2 dapat diganti dengan pola yang lebih baik, misalnya cakupan transaksi (using blok yang mengembalikan transaksi apa pun yang tidak dilakukan selama blok) mempersulit pengembang untuk mendapatkan pola praktik terbaik yang salah.

Misalnya, Anda memiliki aplikasi ASP.Net skala besar. Kesalahan logging bisa melalui ELMAH , tampilan kesalahan bisa menjadi YSoD yang informatif secara lokal dan pesan lokal yang bagus dalam produksi. Koneksi basis data semua dapat melalui lingkup dan usingblok transaksi . Anda tidak perlu satu puntry-catch blok .

TL; DR: Praktik terbaik sebenarnya adalah tidak menggunakan try-catchblok sama sekali.

Keith
sumber
4
@Jorj Anda harus membaca seluruh posting, dan jika Anda masih tidak setuju mungkin akan lebih konstruktif untuk melawan salah satu argumen pendukung saya daripada hanya menyatakan bahwa Anda tidak suka kesimpulan saya. Hampir selalu ada pola yang lebih baik daripada try-catch- itu bisa (sangat kadang-kadang) berguna dan saya tidak berpendapat bahwa Anda tidak boleh menggunakannya, tetapi 99% dari waktu ada cara yang lebih baik.
Keith
Jawaban terbaik sejauh ini - hampir setiap jenis pengembangan .net memiliki semacam PENANGANAN yang jauh lebih cocok untuk menangani pengecualian di tingkat global, membuatnya lebih mudah untuk menanganinya secara konsisten serta membuatnya lebih mudah untuk membiarkannya meledak dalam pengembangan (mengapa ada orang yang ingin menggali melalui file log untuk jejak stack ??) @ Kim, saya akan memimpin dengan TLDR Anda, dan menambahkan beberapa contoh penangan global (yaitu ThreadException, Application_Error, dll). Dengan segala cara menangkap kesalahan SPESIFIK, tetapi gila untuk membungkus metode yang pernah ada dalam try / catch / log
b_levitt
34

Pengecualian adalah kesalahan pemblokiran .

Pertama-tama, praktik terbaik seharusnya jangan melemparkan pengecualian untuk segala jenis kesalahan, kecuali itu adalah kesalahan pemblokiran .

Jika kesalahannya memblokir , maka lontarkan pengecualian. Setelah pengecualian dilemparkan, tidak perlu menyembunyikannya karena itu luar biasa; beri tahu pengguna tentang hal itu (Anda harus memformat ulang seluruh pengecualian untuk sesuatu yang berguna bagi pengguna di UI).

Pekerjaan Anda sebagai pengembang perangkat lunak adalah berusaha untuk mencegah kasus luar biasa di mana beberapa parameter atau situasi runtime dapat berakhir dengan pengecualian. Artinya, pengecualian tidak boleh dibisukan, tetapi ini harus dihindari .

Misalnya, jika Anda tahu bahwa beberapa input integer bisa datang dengan format yang tidak valid, gunakan int.TryParsesajaint.Parse . Ada banyak kasus di mana Anda dapat melakukan ini alih-alih hanya mengatakan "jika gagal, cukup lempar pengecualian".

Melontarkan pengecualian itu mahal.

Jika, setelah semua, pengecualian dilemparkan, alih-alih menulis pengecualian ke log setelah dilempar, salah satu praktik terbaik adalah menangkapnya di penangan pengecualian kesempatan pertama . Sebagai contoh:

  • ASP.NET: Global.asax Application_Error
  • Lainnya: Acara AppDomain.FirstChanceException .

Pendirian saya adalah bahwa percobaan / tangkapan lokal lebih cocok untuk menangani kasus khusus di mana Anda dapat menerjemahkan pengecualian ke kasus lain, atau ketika Anda ingin "membisukan" untuk kasus yang sangat, sangat, sangat, sangat, sangat, sangat istimewa (bug perpustakaan) melempar pengecualian yang tidak terkait yang harus dibisukan untuk menyelesaikan seluruh bug).

Untuk kasus-kasus lainnya:

  • Cobalah untuk menghindari pengecualian.
  • Jika ini tidak memungkinkan: penangan pengecualian kesempatan pertama.
  • Atau gunakan aspek PostSharp (AOP).

Menjawab @thewhiteambit pada beberapa komentar ...

@thewhiteambit berkata:

Pengecualian bukanlah Kesalahan Fatal, mereka Pengecualian! Kadang-kadang itu bahkan bukan Kesalahan, tetapi menganggapnya Fatal-Kesalahan adalah pemahaman yang sepenuhnya salah tentang apa itu Pengecualian.

Pertama-tama, bagaimana pengecualian bahkan tidak bisa kesalahan?

  • Tidak ada koneksi basis data => pengecualian.
  • Format string tidak valid untuk menguraikan beberapa tipe => pengecualian
  • Mencoba mem-parsing JSON dan sementara input sebenarnya bukan pengecualian JSON =>
  • Argumen nullsementara objek diharapkan => pengecualian
  • Beberapa perpustakaan memiliki bug => melempar pengecualian yang tidak terduga
  • Ada koneksi soket dan terputus. Kemudian Anda mencoba mengirim pesan => pengecualian
  • ...

Kami mungkin mencantumkan 1k kasus ketika pengecualian dilemparkan, dan setelah semua, salah satu kasus yang mungkin akan menjadi kesalahan .

Pengecualian adalah kesalahan, karena pada akhirnya itu adalah objek yang mengumpulkan informasi diagnostik - ia memiliki pesan dan itu terjadi ketika terjadi kesalahan.

Tidak ada yang akan melempar pengecualian ketika tidak ada kasus luar biasa. Pengecualian harus memblokir kesalahan karena begitu mereka dilempar, jika Anda tidak mencoba untuk jatuh ke dalam penggunaan try / catch dan pengecualian untuk menerapkan aliran kontrol itu berarti aplikasi / layanan Anda akan menghentikan operasi yang dimasukkan ke dalam kasus luar biasa .

Juga, saya menyarankan semua orang untuk memeriksa paradigma gagal-cepat yang diterbitkan oleh Martin Fowler (dan ditulis oleh Jim Shore) . Ini adalah bagaimana saya selalu mengerti bagaimana menangani pengecualian, bahkan sebelum saya sampai pada dokumen ini beberapa waktu lalu.

[...] menganggap mereka Fatal-Kesalahan adalah pemahaman yang sepenuhnya salah tentang apa pengecualian itu.

Biasanya pengecualian memotong beberapa aliran operasi dan ditangani untuk mengubahnya menjadi kesalahan yang dapat dipahami manusia. Dengan demikian, sepertinya pengecualian sebenarnya adalah paradigma yang lebih baik untuk menangani kasus kesalahan dan bekerja pada mereka untuk menghindari crash aplikasi / layanan lengkap dan memberi tahu pengguna / konsumen bahwa ada kesalahan.

Jawaban lain tentang masalah @thewhiteambit

Misalnya dalam hal Koneksi-Database yang hilang, program dapat melanjutkan menulis ke file lokal dan mengirimkan perubahan ke Database begitu tersedia lagi. Pengecoran String-To-Number Anda yang tidak valid dapat mencoba mengurai lagi dengan interpretasi bahasa-lokal pada Pengecualian, seperti saat Anda mencoba bahasa Inggris default ke Parse ("1,5") gagal dan Anda mencobanya dengan interpretasi Jerman lagi yang sepenuhnya baik karena kita menggunakan koma bukan titik sebagai pemisah. Anda melihat Pengecualian ini bahkan tidak boleh memblokir, mereka hanya perlu beberapa penanganan Pengecualian.

  1. Jika aplikasi Anda dapat bekerja offline tanpa menahan data ke basis data, Anda tidak boleh menggunakan pengecualian , karena menerapkan aliran kontrol try/catchdianggap sebagai anti-pola. Pekerjaan offline adalah kasus penggunaan yang memungkinkan, jadi Anda menerapkan aliran kontrol untuk memeriksa apakah basis data dapat diakses atau tidak, Anda tidak menunggu sampai tidak terjangkau .

  2. Hal parsing juga merupakan kasus yang diharapkan ( bukan KASUS LUAR BIASA ). Jika Anda mengharapkan ini, Anda tidak menggunakan pengecualian untuk melakukan kontrol aliran! . Anda mendapatkan beberapa metadata dari pengguna untuk mengetahui apa budayanya dan Anda menggunakan formatters untuk ini! .NET juga mendukung hal ini dan lingkungan lain, dan pengecualian karena pemformatan angka harus dihindari jika Anda mengharapkan penggunaan khusus aplikasi / layanan Anda .

Pengecualian yang tidak ditangani biasanya menjadi Kesalahan, tetapi Pengecualian itu sendiri bukan codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Artikel ini hanya pendapat atau sudut pandang penulis.

Karena Wikipedia bisa juga hanya pendapat penulis artikel, saya tidak akan mengatakan itu adalah dogma , tetapi periksa apa kata Coding oleh pengecualian artikel di suatu tempat dalam beberapa paragraf:

[...] Menggunakan pengecualian ini untuk menangani kesalahan spesifik yang muncul untuk melanjutkan program disebut pengkodean dengan pengecualian. Anti-pola ini dapat dengan cepat menurunkan perangkat lunak dalam kinerja dan pemeliharaan.

Ia juga mengatakan di suatu tempat:

Penggunaan pengecualian salah

Seringkali pengkodean dengan pengecualian dapat menyebabkan masalah lebih lanjut dalam perangkat lunak dengan penggunaan pengecualian yang salah. Selain menggunakan penanganan eksepsi untuk masalah unik, penggunaan eksepsi yang salah akan mengambil ini lebih jauh dengan mengeksekusi kode bahkan setelah eksepsi dinaikkan. Metode pemrograman yang buruk ini menyerupai metode goto dalam banyak bahasa perangkat lunak tetapi hanya terjadi setelah masalah dalam perangkat lunak terdeteksi.

Jujur, saya percaya bahwa perangkat lunak tidak dapat dikembangkan tidak menganggap serius kasus penggunaan. Jika Anda tahu itu ...

  • Basis data Anda bisa offline ...
  • Beberapa file dapat dikunci ...
  • Beberapa pemformatan mungkin tidak didukung ...
  • Beberapa validasi domain mungkin gagal ...
  • Aplikasi Anda harus berfungsi dalam mode offline ...
  • kasus penggunaan apa pun ...

... Anda tidak akan menggunakan pengecualian untuk itu . Anda akan mendukung kasus penggunaan ini menggunakan aliran kontrol biasa.

Dan jika beberapa use case yang tidak terduga tidak tercakup, kode Anda akan gagal dengan cepat, karena itu akan menimbulkan pengecualian . Benar, karena pengecualian adalah kasus luar biasa .

Di sisi lain, dan akhirnya, kadang-kadang Anda menutup kasus luar biasa dengan melempar pengecualian yang diharapkan , tetapi Anda tidak membuangnya untuk menerapkan aliran kontrol. Anda melakukannya karena Anda ingin memberi tahu lapisan atas bahwa Anda tidak mendukung beberapa use case atau kode Anda gagal bekerja dengan beberapa argumen yang diberikan atau data / properti lingkungan.

Fidemraizer Matías
sumber
6

Satu-satunya saat Anda harus mengkhawatirkan pengguna Anda tentang sesuatu yang terjadi dalam kode adalah jika ada sesuatu yang dapat atau perlu mereka lakukan untuk menghindari masalah tersebut. Jika mereka dapat mengubah data pada formulir, tekan tombol atau ubah pengaturan aplikasi untuk menghindari masalah lalu beri tahu mereka. Tetapi peringatan atau kesalahan yang tidak bisa dihindari pengguna hanya membuat mereka kehilangan kepercayaan terhadap produk Anda.

Pengecualian dan Log adalah untuk Anda, pengembang, bukan pengguna akhir Anda. Memahami hal yang benar untuk dilakukan ketika Anda menangkap setiap pengecualian jauh lebih baik daripada hanya menerapkan beberapa aturan emas atau mengandalkan jaring pengaman aplikasi-lebar.

Pengodean tanpa pikiran adalah HANYA jenis pengkodean yang salah. Fakta bahwa Anda merasa ada sesuatu yang lebih baik yang dapat dilakukan dalam situasi tersebut menunjukkan bahwa Anda diinvestasikan dalam pengkodean yang baik, tetapi hindari mencoba untuk mencap beberapa aturan umum dalam situasi ini dan memahami alasan sesuatu untuk dilemparkan di tempat pertama dan apa Anda dapat melakukannya untuk memulihkannya.

ChrisCW
sumber
6

Saya tahu ini adalah pertanyaan lama, tetapi tidak ada seorang pun di sini yang menyebutkan artikel MSDN, dan itu adalah dokumen yang benar-benar menjelaskannya bagi saya, MSDN memiliki dokumen yang sangat bagus tentang ini, Anda harus menangkap pengecualian ketika kondisi berikut ini benar:

  • Anda memiliki pemahaman yang baik tentang mengapa pengecualian mungkin dilemparkan, dan Anda dapat menerapkan pemulihan tertentu, seperti mendorong pengguna untuk memasukkan nama file baru ketika Anda menangkap objek FileNotFoundException.

  • Anda dapat membuat dan melempar pengecualian baru yang lebih spesifik.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Anda ingin menangani sebagian pengecualian sebelum meneruskannya untuk penanganan tambahan. Dalam contoh berikut, blok tangkap digunakan untuk menambahkan entri ke log kesalahan sebelum melemparkan kembali pengecualian.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Saya sarankan membaca seluruh bagian " Pengecualian dan Penanganan Pengecualian " dan juga Praktik Terbaik untuk Pengecualian .

Hamid Mosalla
sumber
1

Pendekatan yang lebih baik adalah yang kedua (yang mana Anda menentukan jenis pengecualian). Keuntungan dari ini adalah Anda tahu bahwa jenis pengecualian ini dapat terjadi dalam kode Anda. Anda menangani jenis pengecualian ini dan Anda dapat melanjutkan. Jika ada pengecualian lain datang, maka itu berarti ada sesuatu yang salah yang akan membantu Anda menemukan bug dalam kode Anda. Aplikasi pada akhirnya akan macet, tetapi Anda akan mengetahui bahwa ada sesuatu yang Anda lewatkan (bug) yang perlu diperbaiki.

fhnaseer
sumber
1

Dengan Pengecualian, saya mencoba yang berikut:

Pertama, saya menangkap jenis pengecualian khusus seperti pembagian dengan nol, operasi IO, dan seterusnya dan menulis kode sesuai dengan itu. Misalnya, pembagian dengan nol, tergantung pada nilai yang dapat saya berikan kepada pengguna (misalnya kalkulator sederhana di mana dalam perhitungan tengah (bukan argumen) tiba di divisi dengan nol) atau untuk diam-diam memperlakukan pengecualian itu, mencatat dan melanjutkan pemrosesan.

Lalu saya mencoba menangkap pengecualian yang tersisa dan mencatatnya. Jika memungkinkan mengizinkan eksekusi kode, jika tidak beri tahu pengguna bahwa ada kesalahan dan minta mereka mengirim laporan kesalahan.

Dalam kode, kira-kira seperti ini:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}
Sorcerer86pt
sumber
1
Membagi dengan nol pengecualian dan sejenisnya lebih baik ditangani dengan memeriksa 0pembilang sebelumnya, daripada a try-catch. Juga mengapa menangkap obat generik di Exceptionsini? Anda lebih baik membiarkan gelembung kesalahan naik daripada menghadapinya di sini dalam semua kasus di mana Anda tidak mengharapkannya.
Keith
Baca lebih baik apa yang saya tulis tentang contoh yang saya berikan - perhatikan "tidak dalam argumen". Tentu saja kalkulator apa pun harus memverifikasi argumen yang diberikan. Yang saya bicarakan adalah langkah tengah. Pada saat itu verifikasi argumen pengguna sudah terjadi. Juga dalam beberapa aplikasi, lebih baik menghindari pengecualian untuk muncul. Beberapa aplikasi harus memperlakukan pengecualian secara diam-diam, di mana yang lain memperlakukan pengecualian sebagai kesalahan. Server web sebagai contoh harus dijalankan bahkan ketika pengecualian terjadi, di mana perangkat lunak medis (mesin x-ray misalnya) harus dibatalkan ketika pengecualian terjadi.
Sorcerer86pt
Tidak ada aplikasi harus pernah memperlakukan pengecualian diam-diam. Terkadang Anda memiliki pengecualian yang dapat ditangani kode, tetapi penggunaan tersebut harus langka dan spesifik untuk pengecualian yang diharapkan. Contoh server web Anda buruk - ia harus memiliki pengaturan konfigurasi yang memungkinkan Anda memilih cara kesalahan dicatat dan apakah ditampilkan dengan detail atau hanya halaman HTTP 500, tetapi tidak boleh mengabaikan kesalahan secara diam-diam.
Keith
Saya mencoba mencari tahu apa yang sebenarnya memotivasi orang untuk menambahkan satu sinonim lagi untuk "goto." Tetapi sehubungan dengan pembagian dengan nol, ini akan menjadi SATU jenis pengecualian yang dapat saya lihat yang membenarkan peningkatan bahasa. Mengapa? Karena mungkin saja A) nol secara statistik sangat kecil dalam kumpulan data Anda, dan B) menggunakan (memungkinkan) pengecualian mungkin jauh lebih efisien, karena melakukan pembagian adalah salah satu cara untuk menguji pembagi nol. Ketika A dan B benar, eksekusi rata-rata program Anda akan lebih cepat menggunakan pengecualian, dan bahkan mungkin lebih kecil.
Mike Layton
1

Pendekatan kedua adalah yang baik.

Jika Anda tidak ingin menampilkan kesalahan dan membingungkan pengguna aplikasi dengan menunjukkan pengecualian runtime (yaitu kesalahan) yang tidak terkait dengan mereka, maka cukup log kesalahan dan tim teknis dapat mencari masalah dan menyelesaikannya.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Saya sarankan Anda menggunakan pendekatan kedua untuk seluruh aplikasi Anda.

Pranay Rana
sumber
2
Pendekatan kedua tidak menunjukkan kepada pengguna tentang kesalahan yang terjadi - misalnya jika mereka menyimpan sesuatu, mereka tidak akan tahu bahwa itu telah gagal. catchblokir harus selalu memanggil throwuntuk menggelembungkan pengecualian ke atas atau mengembalikan sesuatu / menampilkan sesuatu yang memberi tahu pengguna bahwa tindakan telah gagal. Anda ingin mendapatkan panggilan dukungan ketika mereka gagal menyimpan apa pun itu, bukan 6 bulan kemudian ketika mereka mencoba mengambilnya dan tidak dapat menemukannya.
Keith
0

Meninggalkan blok tangkapan kosong adalah hal terburuk yang harus dilakukan. Jika ada kesalahan, cara terbaik untuk mengatasinya adalah dengan:

  1. Masuk ke file \ database dll.
  2. Cobalah untuk memperbaikinya dengan cepat (mungkin mencoba cara alternatif untuk melakukan operasi itu)
  3. Jika kami tidak dapat memperbaikinya, beri tahu pengguna bahwa ada beberapa kesalahan dan tentu saja batalkan operasi
Stasel
sumber
0

Bagi saya, menangani pengecualian dapat dilihat sebagai aturan bisnis. Jelas, pendekatan pertama tidak dapat diterima. Yang kedua lebih baik dan mungkin 100% cara yang benar JIKA konteksnya mengatakan demikian. Sekarang, misalnya, Anda sedang mengembangkan Outlook Addin. Jika Anda menambahkan melempar pengecualian yang tidak ditangani, pengguna prospek mungkin sekarang mengetahuinya karena prospek tidak akan menghancurkan dirinya sendiri karena satu plugin gagal. Dan Anda mengalami kesulitan untuk mencari tahu apa yang salah. Oleh karena itu, pendekatan kedua dalam hal ini, bagi saya, itu yang benar. Selain mencatat pengecualian, Anda mungkin memutuskan untuk menampilkan pesan kesalahan kepada pengguna - saya menganggapnya sebagai aturan bisnis.

Thai Anh Duc
sumber
0

Praktik terbaik adalah membuang Pengecualian saat kesalahan terjadi. Karena kesalahan telah terjadi dan tidak boleh disembunyikan.

Tetapi dalam kehidupan nyata Anda dapat memiliki beberapa situasi ketika Anda ingin menyembunyikan ini

  1. Anda mengandalkan komponen pihak ketiga dan Anda ingin melanjutkan program jika terjadi kesalahan.
  2. Anda memiliki kasus bisnis yang harus dilanjutkan jika terjadi kesalahan
Gregory Nozik
sumber
6
Tidak Apakah tidak membuang Exception. Pernah. Lemparkan subkelas yang sesuai dari Exceptionsemua yang Anda inginkan, tetapi tidak pernah Exceptionkarena itu sama sekali tidak memberikan informasi semantik. Saya benar-benar tidak dapat melihat skenario di mana masuk akal untuk melempar Exceptiontetapi bukan subkelasnya.
CVn
0

Yang catchtanpa argumen hanyalah memakan pengecualian dan tidak ada gunanya. Bagaimana jika kesalahan fatal terjadi? Tidak ada cara untuk mengetahui apa yang terjadi jika Anda menggunakan tangkapan tanpa argumen.

Pernyataan penangkapan harus menangkap Pengecualian yang lebih spesifik seperti FileNotFoundExceptiondan kemudian pada akhirnya Anda harus menangkap Exceptionyang akan menangkap pengecualian lain dan mencatatnya.

Anirudha
sumber
Mengapa memiliki seorang jenderal catch(Exception)pada akhirnya? Jika Anda tidak mengharapkannya maka itu selalu praktik terbaik untuk meneruskannya ke lapisan berikutnya.
Keith
1
@Keith ya Anda benar ... tidak ada gunanya menangkap pengecualian yang tidak Anda harapkan tetapi Anda dapat pengecualian umum untuk tujuan logging ..
Anirudha
0

Terkadang Anda perlu memperlakukan pengecualian yang tidak mengatakan apa-apa kepada pengguna.

Cara saya adalah:

  • Untuk menangkap pengecualian yang tidak diikuti pada tingkat aplikasi (mis. Di global.asax) untuk pengecualian kritis (aplikasi tidak dapat berguna). Pengecualian ini saya tidak menangkap di tempat. Cukup login pada level aplikasi dan biarkan sistem melakukan tugasnya.
  • Tangkap "di tempat" dan tampilkan beberapa info bermanfaat kepada pengguna (masukkan nomor yang salah, tidak dapat diuraikan).
  • Tangkap di tempat dan jangan lakukan apa pun pada masalah marginal seperti "Saya akan memeriksa info pembaruan di latar belakang, tetapi layanan tidak berjalan".

Ini jelas tidak harus menjadi praktik terbaik. ;-)

Fanda
sumber
0

Saya bisa memberitahumu sesuatu:

Cuplikan # 1 tidak dapat diterima karena mengabaikan pengecualian. (Menelannya seperti tidak ada yang terjadi).

Jadi jangan tambahkan catch block yang tidak melakukan apa-apa atau hanya rethrows.

Tangkapan blok harus menambahkan beberapa nilai. Misalnya pesan keluaran untuk pengguna akhir atau kesalahan log.

Jangan gunakan pengecualian untuk logika program aliran normal. Sebagai contoh:

misalnya validasi input. <- Ini bukan situasi luar biasa yang valid, melainkan Anda harus menulis metode IsValid(myInput);untuk memeriksa apakah item input valid atau tidak.

Kode desain untuk menghindari pengecualian. Sebagai contoh:

int Parse(string input);

Jika kita memberikan nilai yang tidak dapat diuraikan ke int, metode ini akan membuang dan pengecualian, alih-alih kita dapat menulis sesuatu seperti ini:

bool TryParse(string input,out int result); <- metode ini akan mengembalikan boolean yang menunjukkan jika parse berhasil.

Mungkin ini sedikit di luar ruang lingkup pertanyaan ini, tetapi saya harap ini akan membantu Anda untuk membuat keputusan yang tepat ketika itu tentang try {} catch(){}dan pengecualian.

Roxy'Pro
sumber