Bagaimana saya harus memberikan informasi tambahan tentang pengecualian?

20

Setiap kali saya perlu memberikan informasi tambahan tentang pengecualian saya bertanya-tanya di mana sebenarnya cara yang tepat untuk melakukan ini.


Demi pertanyaan ini, saya menulis sebuah contoh. Anggap ada kelas tempat kita ingin memperbarui Abbreviationproperti. Dari sudut pandang SOLID itu mungkin tidak sempurna tetapi bahkan jika kita melewati metode pekerja melalui DI dengan beberapa layanan situasi yang sama akan terjadi - pengecualian terjadi dan tidak ada konteks untuk itu. Kembali ke contoh ...

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Abbreviation { get; set; }
}

Kemudian ada beberapa instance dari kelas dan loop di mana metode pekerja dipanggil. Itu bisa melempar StringTooShortException.

var persons =
{
    new Person { Id = 1, Name = "Fo" },
    new Person { Id = 2, Name = "Barbaz" },
}

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            // ?
        }
    }
    // throw AggregateException...
}

public IEnumerable<string> GenerateAbbreviation(string value)
{
    if (value.Length < 5)
    {
        throw new StringTooShortException(value);
    }

    // generate abbreviation
}

Pertanyaannya adalah: bagaimana cara menambahkan Personatau nya Id(atau apa pun)?


Saya tahu tiga teknik berikut:


1 - Gunakan Dataproperti

Pro:

  • mudah untuk mengatur informasi tambahan
  • tidak perlu membuat lebih banyak pengecualian
  • tidak memerlukan tambahan try/catch

Kekurangan:

  • tidak dapat dengan mudah diintegrasikan ke dalam Message
  • penebang mengabaikan bidang ini dan tidak akan membuangnya
  • membutuhkan kunci dan casting karena nilai-nilai ini object
  • tidak kekal

Contoh:

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            ex.Data["PersonId"] = person.Id;
            // collect ex
        }
    }
    // throw AggregateException...
}

2 - Gunakan properti khusus

Pro:

  • mirip dengan Dataproperti tetapi sangat diketik
  • lebih mudah diintegrasikan ke dalam Message

Kekurangan:

  • membutuhkan pengecualian khusus
  • logger akan mengabaikannya
  • tidak kekal

Contoh:

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            // not suitable for this exception because 
            // it doesn't have anything in common with the Person
        }
    }
    // throw AggregateException...
}

3 - Bungkus pengecualian dengan pengecualian lain

Pro:

  • Message dapat diformat dengan cara yang dapat diprediksi
  • penebang akan membuang pengecualian dalam
  • abadi

Kekurangan:

  • membutuhkan tambahan try/catch
  • menambah sarang
  • meningkatkan kedalaman eksepsi

Contoh:

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            try
            {
                person.Abbreviation = GenerateAbbreviation(person.Name);
            }
            catch(Exception ex)
            {
                throw new InvalidPersonDataException(person.Id, ex);
            }
        }
        catch(Exception ex)
        {
            // collect ex
        }
    }
    // throw AggregateException...
}

  • Apakah ada pola lain?
  • Apakah ada pola yang lebih baik?
  • Bisakah Anda menyarankan praktik terbaik untuk salah satu dari mereka?
t3chb0t
sumber
Tidak terbiasa dengan pengecualian dalam C # tapi saya biasanya berharap contoh Person masih valid ketika pengecualian dilemparkan. Sudahkah Anda mencobanya?
John Kouraklis
1
@JohnKouraklis bukan ini pertanyaannya ;-) Ini hanya contoh yang sangat sederhana untuk menunjukkan apa yang saya maksud dengan informasi tambahan. Jika saya memposting di sini seluruh kerangka kerja di mana metode mutliple dapat melemparkan pengecualian dan tingkat mutliple informasi konteks harus disediakan tidak ada yang mungkin akan membaca ini dan saya memiliki waktu yang sangat sulit untuk menjelaskannya.
t3chb0t
@JohnKouraklis Saya baru saja membuatnya untuk tujuan demonstrasi.
t3chb0t
@ t3chb0t Saya pikir Anda sudah menjawab pertanyaan Anda sendiri di sini. Pertimbangkan memindahkan 1, 2, & 3 menjadi jawaban dan menyesuaikan pertanyaan Anda sehingga tidak meminta saya untuk memilih gaya berdasarkan pendapat saya.
candied_orange
Apa yang salah dengan pengecualian khusus? Dilakukan dengan benar, mereka adalah bagian dari bahasa domain Anda dan membantu mencapai abstraksi dari detail implementasi.
RubberDuck

Jawaban:

6

Data FTW .

"Kontra" Anda:

  • "tidak dapat dengan mudah diintegrasikan ke dalam Pesan"

-> Untuk jenis pengecualian Anda , itu harus cukup mudah untuk ditimpa Messagesehingga tidak tergabung Data.. meskipun saya hanya akan mempertimbangkan ini jika Datapesannya .

  • "Penebang mengabaikan bidang ini dan tidak akan membuangnya"

Googling untuk Nlog sebagai contoh menghasilkan :

Penyaji tata letak pengecualian

(...)

format - Format output. Harus daftar dipisahkan koma sifat pengecualian: Message, Type, ShortType, ToString, Method, StackTrace& Data. Nilai parameter ini tidak peka huruf besar-kecil. Default:message

Jadi sepertinya itu mudah dikonfigurasi.

  • membutuhkan kunci dan casting karena nilai adalah objek

Hah? Cukup buang benda-benda di sana dan pastikan mereka memiliki yang dapat digunakanToString() metode yang digunakan.

Juga, saya tidak melihat masalah dengan kunci. Cukup gunakan keunikan ringan dan Anda baik-baik saja.


Penafian: Ini adalah apa yang saya dapat segera lihat dari pertanyaan dan apa yang saya googled Datadalam 15 menit. Saya pikir ini agak membantu, jadi saya mengeluarkannya sebagai jawaban, tetapi saya tidak pernah menggunakan Datadiri saya sendiri, jadi mungkin saja si penanya di sini tahu lebih banyak tentang hal ini daripada saya.

Martin Ba
sumber
Saya sampai pada kesimpulan bahwa hanya ada dua hal tentang pengecualian yang bermanfaat, nama dan pesannya. Segala sesuatu yang lain hanyalah suara tidak berguna yang dapat dan harus diabaikan karena terlalu rapuh.
t3chb0t
2

Mengapa Anda melempar Pengecualian? Agar mereka ditangkap dan ditangani.

Bagaimana cara kode penangkapan mengetahui cara menangani Pengecualian? Menggunakan properti yang Anda tetapkan pada objek Pengecualian.

Jangan pernah menggunakan properti Pesan untuk mengidentifikasi pengecualian, atau untuk memberikan "informasi" yang harus diandalkan oleh penangan potensial. Itu terlalu mudah berubah dan tidak dapat diandalkan.

Saya tidak pernah menggunakan properti "Data" sebelumnya tetapi kedengarannya terlalu generik bagi saya.

Kecuali jika Anda membuat banyak kelas Pengecualian, yang masing-masing mengidentifikasi kasus Luar Biasa tertentu , bagaimana Anda tahu kapan Anda menangkap Pengecualian yang diwakili oleh "Data"? (Lihat komentar sebelumnya tentang "Pesan").

Phill W.
sumber
1
Saya katakan, Datatidak berguna untuk penanganan, tetapi berharga untuk logging untuk menghindari Messagepemformatan neraka.
Martin Ba
-1

Saya suka contoh ketiga Anda, namun ada cara lain yang bisa dikodekan untuk menghilangkan sebagian besar "con" Anda.

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    var exceptions = new List<InvalidPersonDataException>();

    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            exceptions.Add(new InvalidPersonDataException(person.Id, ex));
        }
    }

    if (exceptions.Any())
    {
        throw new AggregateException(exceptions);
    }
}
krillgar
sumber