Bir istisna hakkında nasıl ek bilgi vermeliyim?


20

Her seferinde aslında yolu bir istisna ben merak hakkında ek bilgi sağlamak için gereken doğru Bunu yapmanın yolu.


Bu soru uğruna bir örnek yazdım. Varsayalım ki Abbreviationözelliği güncellemek istediğimiz bir sınıf var . SOLID bakış açısından mükemmel olmayabilir, ancak işçi yöntemini DI üzerinden bir hizmetle geçsek bile aynı durum ortaya çıkar - bir istisna oluşur ve bunun için bir bağlam yoktur. Örneğe dön ...

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

Sonra sınıfın bazı örnekleri ve worker-method'un çağrıldığı bir döngü vardır. O atabilir 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
}

Soru şudur: Personveya Id(veya başka bir şey) nasıl eklenir ?


Aşağıdaki üç tekniği biliyorum:


1 - DataMülkü kullanın

Artıları:

  • kolay ek bilgi ayarlama
  • daha fazla istisna oluşturmayı gerektirmez
  • ek gerektirmez try/catch

Eksileri:

  • kolayca entegre edilemez Message
  • kaydediciler bu alanı yok sayar ve boşaltılamaz
  • anahtarlar gerektirir ve döküm neden değerleri object
  • değişmez

Misal:

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 - Özel özellikleri kullanma

Artıları:

  • Datamülke benzer ancak güçlü bir şekilde yazılmış
  • entegre etmek daha kolay Message

Eksileri:

  • özel istisnalar gerektirir
  • Logger onları görmezden gelecek
  • değişmez

Misal:

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 - İstisnayı başka bir istisna ile sarın

Artıları:

  • Message öngörülebilir bir şekilde biçimlendirilebilir
  • kaydediciler iç istisnaları atar
  • değişmez

Eksileri:

  • ek gerektirir try/catch
  • Increses nesting
  • istisnaların derinliğini arttırır

Misal:

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...
}

  • Başka kalıplar var mı?
  • Daha iyi kalıplar var mı?
  • Herhangi biri / hepsi için en iyi uygulamaları önerebilir misiniz?

C # istisnalarına aşina değilim ama normalde istisna atıldığında Person örneğinin hala geçerli olmasını beklerdim. Bunu denedin mi?
John Kouraklis

1
@JohnKouraklis bu sorunun ne olduğunu değil ;-) Ek bilgi ile ne demek istediğimi göstermek için son derece basit bir örnek. Burada, çoklu yöntemlerin istisnalar atayabileceği ve bağlam bilgilerinin çoklu seviyelerini atabileceği bir çerçeve yayınlasaydım, hiç kimse muhtemelen bunu okumazdı ve bunu açıklamak için gerçekten zor zamanım vardı.
t3chb0t

@JohnKouraklis Gösteri amacıyla yeni uydurdum.
t3chb0t

@ t3chb0t Sanırım burada kendi sorunuzu cevapladınız. 1, 2 ve 3'ü bir cevaba taşımayı ve sorunuzu, bence bir stil seçmemi istemeyecek şekilde ayarlamayı düşünün.
candied_orange

Özel istisnaların sorunu nedir? Doğru şekilde yapılırsa, alan adı dilinizin bir parçasıdır ve uygulama ayrıntılarından soyutlama elde etmenize yardımcı olurlar.
RubberDuck

Yanıtlar:


6

Data FTW .

"Kontra" nız:

  • "İletiye kolayca entegre edilemez"

-> için sizin istisna tipleri, geçersiz kılmak için kolay yeterli olacaktır Messagebu nedenle bu does birleştirmek Dataise yalnızca bu dikkate alacağını rağmen .. Datamesajdır .

  • "kaydediciler bu alanı yok sayar ve boşaltılamaz"

Bir örnek olarak nlog Googling verim :

İstisna düzeni oluşturucu

(...)

format - Çıktının formatı. İstisna özelliklerinin virgülle ayrılmış bir liste olmalıdır: Message, Type, ShortType, ToString, Method, StackTraceve Data. Bu parametre değeri büyük / küçük harfe duyarlı değildir. Varsayılan:message

Görünüşe göre bu kolayca yapılandırılabilir.

  • değerler nesne olduğundan anahtarlar ve döküm gerektirir

Ha? Sadece nesneleri oraya dökün ve kullanılabilir bir ToString()yöntem olduğundan emin olun .

Ayrıca, tuşlarla ilgili herhangi bir sorun görmüyorum. Sadece hafif bir teklik kullanın ve iyisiniz.


Feragatname: Bu, sorudan hemen görebildiğim ve Data15 dakika içinde neyi araştırdığım . Hafif yardımcı olduğunu düşündüm, bu yüzden bir cevap olarak ortaya koydum, ama Datakendimi hiç kullanmadım , bu yüzden burada soru soran kişi benden daha fazla şey biliyor olabilir.


Bir istisna ile ilgili sadece iki şey olduğu sonucuna vardım, adı ve mesajı. Diğer her şey göz ardı edilebilir ve göz ardı edilmesi gereken yararsız bir gürültüdür çünkü ona çok kırılgan bir şekilde güvenir.
t3chb0t

2

Neden İstisnalar atıyorsunuz? Onları yakalayıp halletmek için.

Yakalama kodu İstisna ile nasıl başa çıkmaktadır ? Özel Durum nesnesinde tanımladığınız özellikleri kullanma.

Hiçbir zaman özel durumu tanımlamak veya potansiyel işleyicilerin güvenmesi gereken "bilgi" sağlamak için Message özelliğini kullanmayın. Çok uçucu ve güvenilmez.

Daha önce hiç "Veri" özelliğini kullanmadım ama bana çok genel geliyor.

Her biri belirli bir İstisnai durumu tanımlayan çok sayıda İstisna sınıfı oluşturmazsanız , "Verilerin" neyi temsil ettiği İstisna'yı yakaladığınızda nasıl bilebilirsiniz ? ("Mesaj" hakkındaki önceki yoruma bakın).


1
Diyorum ki, Dataidare etmek için işe yaramaz, ama Messagecehennemi biçimlendirmekten kaçınmak için giriş yapmak için değerli .
Martin Ba

-1

Ben üçüncü örneğinizi seviyorum, ancak "con" lar çoğunu ortadan kaldırmak için kodlanmış olabilir başka bir yolu var.

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);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.