Yakalama kullanmak için özel olarak istisnalar oluşturma


10

if...elseKural dışı durum işleme ile sarılmış tipik bir örnek için, aşağıdaki örnek gibi bir şey kod çoğaltmasını önlemek için önerilen bir uygulama mıdır?

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

onun yerine...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

Hafif bir performans isabeti olduğunu biliyorum, ancak bunun kabul edilebilir bir uygulama olarak kabul edilip edilmediğini merak ediyorum. Şu anda ikinci yöntemi yapıyorum - özellikle de belirli istisnaları farklı bir şekilde ele almam gereken durumlarda - ama ilk yöntemin basit durumlar için uygun olup olmadığını merak ediyordum.


yöntem yeterince küçükse ben sadece başka kaldırmak ve trycatch bloğunun dışında null dönecek, bu yüzden sadece bir kez null dönmek zorunda.
Fabio Marcolini

Yanıtlar:


12

Akış denetimi için özel durum işleme kullanımı Microsoft tarafından önerilmez.

Ve konuyla ilgili yuvarlak bir masa var.

Olduğu söyleniyor, C # bunu destekliyor ve bir istisna en uygun yanıt olup olmadığı karşılaşılan duruma bağlıdır varsayalım.


1
Bu tür şeylerin olayları kullanmamak için çok uğraştığı bana çarpıcı geliyor.
radarbob

@radarbob: Olaylar bununla nasıl bağlantılı?

@grovesNL - Bir catch bloğunda belirli bir yöntemi çağırmak için belirli bir noktada bir istisna atmak mı? Quacks benim için bir etkinlik gibi.
radarbob

@radarbob: Bu bir olay değil. Yanıtın yuvarlak masa bağlantısında tartışıldığı gibi bunun kullanılacağı birçok örnek kullanım örneği vardır.

1
@radarbob İstisnalar, çağrılan yöntemin işleyemediği bir şeyin oluştuğunu bildiren bir yol olarak tasarlanmıştır. Ancak, bir olayın dinlenmesi gerekir. Bir istisna, bir programın normal akışının zorla kesilmesidir. Yakalanmayan bir istisna, tüm uygulamanın iptal edilmesine neden olur.

6

Bu cevapta açıklandığı gibi, performans isabeti büyük olasılıkla ihmal edilebilir .

Bu yüzden performansın bir sorun olmadığı fikrine geçelim. Sen atıyorlar System.Exception, sadece içine yürütülmesine taşımak için catchfıkra . A atmak BadControlFlowThatShouldBeRewrittenExceptionmuhtemelen aşırıya kaçmış olurdu.

Bunu parçalayalım. Sahibiz:

  • Yöntem GetDataFromServer(yöntem adları C # içinde PascalCase olmalıdır) bool.
  • Sonuç buysa true, çalıştırın ProcessData.
  • nullAksi takdirde geri dönün .

Bu kodun yazıldığı yönteme benziyor, çok fazla şey yapıyor. GetDataFromServerBir dönen boolbir tasarım hatası gibi görünüyor, ben bu yöntemi bekliyor olurdu o sunucudan gidiyor veri döndürecek , bazı IEnumerable<SomeType>yani mutlu yol döner - 0 veya daha fazla öğe içerecektir n öğeleri n> 0 -so-mutlu değil, path 0 öğe döndürür ve mutsuz yol işlenmemiş bir istisna ile patlar, her neyse.

Bu, yöntemin görünüşünü çok değiştirir - yine bunun mantıklı olup olmadığını söylemek zordur, çünkü orijinal yazı sadece bir çıkış noktasına sahiptir (ve böylece tüm kod yolları bir değer döndürmediği için derlenmeyecektir ), bu sadece vahşi bir tahmin:

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

Burada ProcessData, onun yinelendiğini görürsünüz resultve nullöğesinde hiçbir öğe yoksa geri döner IEnumerable.

Şimdi yöntem neden geri dönüyor null? Sunucu çöktü mü? Sorguda bir hata var mı? Bağlantı dizesi yanlış kimlik bilgilerini kullanıyor mu? Beklemediğiniz GetDataFromServerbir istisna ile patladığında, yutuyor, halının altına itiyor ve bir nulldeğer döndürüyorsunuz . Bu durumda belirli istisnaları yakalamanızı ve diğer her şeyi günlüğe kaydetmenizi öneririm; hata ayıklama bu şekilde çok daha kolay olacaktır.

catchİstisnayı yakalamayan genel bir maddeyle, hiçbir şeyi teşhis etmek oldukça zorlaşır. Bunun yerine minimal olarak yapardım:

catch(Exception e)
{
    return null;
}

Şimdi en azından bir eşeyler ters gidip gitmediğini inceleyebilir ve inceleyebilirsiniz .


TL; DR : Hayır, akış kontrolü için istisnalar atmak ve yakalamak iyi bir fikir değil.


Bu cevap tam olarak neden kodumu genel tutmaya çalıştım gösterir: Aslında benim kod yaptığım her istisna listelemek istemiyordu; Gerçek yöntem adlarını listelemek istemedim; Yöntem bildirimini listelemek istemedim; Sözdizimi önerileri istemiyordum. Akış kontrolü için istisnaları atmanın iyi olup olmadığı hakkında tek bir sorum vardı, ki bu B2K tarafından derhal cevaplandı. Bunu meta üzerinde tartışmaktan memnuniyet duyarım.

3
bunun gibi sesler Programcılar için bir soru olmalı. kodu inceleriz, fikirleri değil.
Malachi

2

ilk cevabınızda, orada olması gerekmeyen bir performans isabeti var.

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

if deyiminden çıktığınızda Catch deyimine girmek için kod değiştirme yönleri yapmanız gerekmediğinde, diyelim.

return null; bunu else deyiminden atıldıktan sonra yakalanan bir yakalamada değil else deyiminde yapmak istiyorsanız .

Muhtemelen Gerçek kodunuz için geçerli değildir , ancak verdiğiniz Genel kod için geçerlidir.

Standartlar bunu yapmamanız gerektiğini söylüyor.

Standartlar bunu böyle yapmanız gerektiğini söylüyor (yine OP'de verilen Genel Kod'a dayanarak)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

ve yakaladığınız özel bir istisnanız olmadığından, burada bir deneme yakalamanız bile olmamalıdır.

İstisnalar oluştuğunda sorunu görmek için İstisnalar meydana geldiğinde görmek istersiniz.


1

Neden bu kadar basit değil:

if (!GetDataFromServer()) return null;
ProcessData();

Bir istisna işleyici mevcut olacaksa, bu işlem ProcessData () içinde olmalıdır


Neden istisnaları ProcessData()en üst düzeye taşımak istemiyorum ?
grovesNL

@grovesNL Buradaki istisna dışında yararlı hiçbir şey yapılmıyordu.
Loren Pechtel

1
Nasıl yani? Eğer ProcessData()bir istisna atar şimdi ele değil. Kendini değiştirmeden bir istisna atarsa return nullbu seviyede olmasını istiyorum . ProcessData()ProcessData()
grovesNL
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.