Pertanyaan C #: Melempar Praktik Terbaik Pengecualian Kustom


Saya telah membaca beberapa pertanyaan lain tentang C # Exception Handling Practices tetapi tidak ada yang bertanya apa yang saya cari.

Jika saya menerapkan Pengecualian khusus saya sendiri untuk kelas atau sekumpulan kelas tertentu. Haruskah semua kesalahan yang berhubungan dengan kelas-kelas itu dienkapsulasi ke dalam pengecualian saya menggunakan pengecualian dalam atau haruskah saya membiarkannya gagal?

Saya berpikir akan lebih baik untuk menangkap semua pengecualian sehingga pengecualian dapat segera dikenali dari sumber saya. Saya masih melewati pengecualian asli sebagai pengecualian batin. Di sisi lain, saya berpikir itu akan berlebihan untuk mengulang pengecualian.

Pengecualian:

class FooException : Exception
{
    //...
}

Opsi 1: Foo encasulates semua Pengecualian:

class Foo
{
    DoSomething(int param)
    {
        try 
        {
             if (/*Something Bad*/)
             {  
                 //violates business logic etc... 
                 throw new FooException("Reason...");
             }
             //... 
             //something that might throw an exception
        }
        catch (FooException ex)
        {
             throw;
        }
        catch (Exception ex)
        {
             throw new FooException("Inner Exception", ex);
        }
    }
}

Opsi 2: Foo melempar FooExceptions spesifik tetapi memungkinkan Pengecualian lain untuk gagal:

class Foo
{
    DoSomething(int param)
    {
        if  (/*Something Bad*/)
        {
             //violates business logic etc... 
             throw new FooException("Reason...");
        }
        //... 
        //something that might throw an exception and not caught
    }
}

46
2018-01-21 16:30


asal


Jawaban:


Berdasarkan pengalaman saya dengan perpustakaan, Anda harus membungkus semuanya (yang dapat Anda antisipasi) dalam a FooException untuk beberapa alasan:

  1. Orang-orang tahu itu berasal dari kelas Anda, atau setidaknya, penggunaan mereka. Jika mereka melihatnya FileNotFoundException mereka mungkin mencari di mana-mana. Anda membantu mereka mempersempitnya. (Saya menyadari sekarang bahwa jejak stack melayani tujuan ini, jadi mungkin Anda dapat mengabaikan hal ini.)

  2. Anda dapat memberikan lebih banyak konteks. Membungkus FNF dengan pengecualian Anda sendiri, Anda dapat mengatakan "Saya mencoba memuat file ini untuk tujuan ini, dan tidak dapat menemukannya. Ini mengisyaratkan kemungkinan solusi yang tepat.

  3. Perpustakaan Anda dapat menangani pembersihan dengan benar. Jika Anda membiarkan gelembung pengecualian, Anda memaksa pengguna untuk membersihkan. Jika Anda benar mengenkapsulasi apa yang Anda lakukan, maka mereka tidak tahu bagaimana menangani situasinya!

Ingatlah untuk hanya membungkus pengecualian yang dapat Anda antisipasi, sukai FileNotFound. Jangan hanya membungkus Exception dan berharap yang terbaik.


53
2018-01-21 16:36



Lihatlah ini Praktik terbaik MSDN.

Pertimbangkan untuk digunakan throw dari pada throw ex jika Anda ingin mengecap ulang pengecualian yang tertangkap, karena dengan cara ini stacktrace asli tetap dipertahankan (nomor baris, dll.).


18
2018-01-21 16:37



Saya selalu menambahkan beberapa properti saat membuat pengecualian khusus. Salah satunya adalah nama pengguna atau ID. Saya menambahkan properti DisplayMessage untuk membawa teks agar ditampilkan kepada pengguna. Kemudian, saya menggunakan properti Pesan untuk menyampaikan detail teknis untuk dicatat dalam log.

Saya menangkap setiap kesalahan dalam Data Access Layer pada tingkat di mana saya masih bisa menangkap nama prosedur yang tersimpan dan nilai-nilai parameter yang dilewatkan. Atau SQL inline. Mungkin nama database atau string koneksi parsial (tidak ada kredensial, silakan). Mereka bisa masuk Pesan atau di properti DatabaseInfo kustom baru mereka sendiri.

Untuk halaman web, saya menggunakan pengecualian khusus yang sama. Saya akan memasukkan properti Pesan informasi formulir - apa yang telah dimasukkan pengguna ke setiap kontrol entri data pada halaman web, ID dari item yang sedang diedit (pelanggan, produk, karyawan, apa pun), dan tindakan pengguna mengambil ketika pengecualian terjadi.

Jadi, strategi saya sesuai pertanyaan Anda adalah: hanya tangkap ketika saya bisa melakukan sesuatu tentang pengecualian. Dan cukup sering, yang bisa saya lakukan hanyalah mencatat detailnya. Jadi, saya hanya menangkap pada titik di mana detail tersebut tersedia, dan kemudian rethrow untuk membiarkan gelembung pengecualian ke UI. Dan saya mempertahankan pengecualian asli dalam pengecualian khusus saya.


6
2018-01-21 16:44



Tujuan pengecualian khusus adalah untuk memberikan informasi kontekstual yang terperinci ke stacktrace untuk membantu dalam debugging. Opsi 1 lebih baik karena tanpa itu, Anda tidak mendapatkan "asal" pengecualian jika itu terjadi "lebih rendah" dalam tumpukan.


3
2018-01-21 16:34



jika Anda menjalankan cuplikan kode untuk 'Pengecualian' dalam Visual Studio, Anda memiliki template penulisan pengecualian praktik yang baik.


1
2018-01-21 16:34



Catatan


1
2018-01-21 16:34



Hal yang paling penting bagi kode untuk mengetahui saat menangkap pengecualian, yang sayangnya benar-benar hilang dari objek Exception, adalah keadaan sistem relatif terhadap apa yang "seharusnya" terjadi (mungkin pengecualian itu dilemparkan karena ada sesuatu yang salah). Jika kesalahan terjadi dalam metode LoadDocument, mungkin dokumen tidak berhasil dimuat, tetapi setidaknya ada dua kemungkinan status sistem:

  1. Status sistem mungkin seolah-olah beban tidak pernah dicoba. Dalam hal ini, akan sangat tepat bagi aplikasi untuk melanjutkan jika dapat melakukannya tanpa dokumen yang dimuat.
  2. Status sistem mungkin cukup rusak sehingga tindakan terbaik adalah menyelamatkan apa yang dapat disimpan ke file 'pemulihan' (hindari mengganti file baik pengguna dengan data yang mungkin rusak) dan matikan.

Jelas akan sering ada negara lain yang mungkin di antara ekstrem itu. Saya akan menyarankan bahwa seseorang harus berusaha untuk memiliki pengecualian khusus yang secara eksplisit menunjukkan bahwa keadaan # 1 ada, dan mungkin satu untuk # 2 jika keadaan yang diperkirakan tetapi tidak dapat dihindari dapat menyebabkannya. Pengecualian apa pun yang terjadi dan akan mengakibatkan negara bagian # 1 harus dibungkus dalam objek pengecualian yang menunjukkan keadaan # 1. Jika pengecualian dapat terjadi sedemikian rupa sehingga status sistem dapat dikompromikan, mereka harus dibungkus sebagai # 2 atau diizinkan untuk meresap.


1
2018-03-22 18:21



Opsi 2 adalah yang terbaik. Saya percaya praktik terbaik adalah hanya menangkap pengecualian ketika Anda berencana melakukan sesuatu dengan pengecualian.

Dalam hal ini, Opsi 1 hanya membungkus pengecualian dengan pengecualian Anda sendiri. Ini tidak menambah nilai dan pengguna kelas Anda tidak lagi dapat menangkap ArgumentException, misalnya, mereka juga perlu menangkap FooException Anda kemudian melakukan parsing pada pengecualian batin. Jika pengecualian batin bukan pengecualian mereka dapat melakukan sesuatu yang berguna dengan mereka perlu rethrow.


0
2018-01-21 16:35