Acıyan istisnalar atmamak nasıl?


21

Eric Lippert'in istisnalar hakkındaki makalesini okumak , hem üretici hem de tüketici olarak istisnalara nasıl yaklaşmam gerektiği konusunda kesinlikle bir göz açıcıydı. Bununla birlikte, hala rahatsız edici istisnalar atmamaktan kaçınmak için bir kılavuz tanımlamakta zorlanıyorum.

özellikle:

  • Başarısız olabilecek bir Kaydet yöntemine sahip olduğunuzu varsayalım, çünkü a) Başkası kaydı sizden önce değiştirdi veya b) Oluşturmaya çalıştığınız değer zaten var . Bu şartlar beklenir ve istisnai değildir, bu nedenle bir istisna atmak yerine, kaydetmenin başarılı olup olmadığını belirten bir boolean döndüren yönteminizin TrySave sürümünü deneyin. Ancak başarısız olursa, tüketici sorunun ne olduğunu nasıl bilecek? Yoksa sonucu belirten bir numara döndürmek en iyisidir, ne tür bir Ok / RecordAlreadyModified / ValueAlreadyExists? İnteger.TryParse ile bu problem mevcut değildir, çünkü yöntemin başarısız olmasının tek bir nedeni vardır.
  • Önceki örnek gerçekten sinir bozucu bir durum mu? Yoksa bu durumda bir istisna atmak tercih edilen yol olabilir mi? Entity çerçevesi de dahil olmak üzere çoğu kütüphanede ve çerçevede böyle yapıldığını biliyorum.
  • Yöntemin çalışıp çalışmadığını önceden test etmek için bir yöntem sağlayarak, yönteminizin bir Dene sürümünü ne zaman oluşturacağınıza nasıl karar verirsiniz? Şu anda bu yönergeleri takip ediyorum:
    • Bir yarış koşulu olasılığı varsa, bir Dene sürümü oluşturun. Bu, tüketicinin dışsal bir istisna yakalama ihtiyacını önler. Örneğin, daha önce açıklanan Kaydet yönteminde.
    • Durumu test etme yöntemi, orijinal yöntemin yaptığı her şeyi yaparsa, bir Try sürümü oluşturun. Örneğin, integer.TryParse ().
    • Başka bir durumda, durumu test etmek için bir yöntem oluşturun.

1
Başarısız olabilecek bir tasarruf örneğiniz gerçekten korkunç bir istisna değildir. Oldukça sıradan ve muhtemelen basit bir istisna olmalı .
S.Lott,

@ S.Lott: Oldukça sıradan derken ne demek istiyorsun? Durumun kendisi mi, yoksa bu durumda bir istisna mı? Her neyse, bunun gerçekten sinir bozucu bir durum olup olmadığı belli olmadığı konusunda size katılıyorum. Soruyu güncelleyeceğim.
Mike,

"Durumun kendisi ya da bu durumda bir istisna atmak" Her ikisi de.
S.Lott,

Yanıtlar:


24

Başarısız olabilecek bir Kaydet yöntemine sahip olduğunuzu varsayalım, çünkü a) Biri daha önce kaydı değiştirdi veya b) Oluşturmaya çalıştığınız değer zaten var. Bu şartlar beklenir ve istisnai değildir, bu nedenle bir istisna atmak yerine, kaydetmenin başarılı olup olmadığını belirten bir boolean döndüren yönteminizin TrySave sürümünü deneyin. Ancak başarısız olursa, tüketici sorunun ne olduğunu nasıl bilecek?

İyi soru.

Aklıma gelen ilk soru şudur: eğer veriler zaten oradaysa, kaydetme hangi anlamda başarısız oldu ? Bana başarılı oldu gibi geliyor eminim. Fakat argüman uğruna, bir operasyonun neden başarısız olabileceğine dair birçok farklı nedeninizin olduğunu varsayalım.

Aklıma gelen ikinci soru şudur: Kullanıcıya geri dönmek istediğiniz bilgiler uygulanabilir mi? Yani, bu bilgilere dayanarak bir karar verecekler mi?

"Motor kontrol edin" ışığı yandığında, kaputu açarım, arabamda yanmayan bir motor olduğunu doğrulayın ve garaja götürün. Elbette garajda, kontrol motoru ışığının neden yandığını söyleyen her türlü özel amaçlı teşhis ekipmanına sahipler, ancak benim görüşüme göre , uyarı sistemi iyi tasarlanmış. Sorunun, oksijen sensörünün yanma odasında anormal bir oksijen seviyesi kaydetmesi nedeniyle veya rölanti devri dedektörü fişinin çekilmemiş olması veya herhangi bir şekilde olması nedeniyle umurumda değil. Aynı işlemi yapacağım, başka birisinin bunu çözmesine izin vereceğim .

Arayan kişi tasarrufun neden başarısız olduğunu önemsiyor mu? Bu konuda vazgeçmek ya da tekrar denemek dışında bir şey yapacaklar mı?

Argüman uğruna, işlemin başarısız olmasının nedenine bağlı olarak arayanın gerçekten farklı işlemler yapacağını varsayalım.

Akla gelen üçüncü soru şudur: başarısızlık modu istisnai midir? Sana kafa karıştırıcı olabileceğini düşünüyorum mümkün olan sakatlıklar . İki kullanıcının aynı kaydı, aynı anda olağan bir durum değil, istisnai ama mümkün bir durumla değiştirmeye çalıştığını düşünürdüm.

Tartışması uğruna istisnasız olduğunu varsayalım.

Akla gelen dördüncü soru şudur: Önümüzdeki kötü durumu güvenilir bir şekilde saptamanın bir yolu var mı?

Kötü durum benim "dışsal" kovamdaysa, hayır. "Başka bir kullanıcı bu kaydı değiştirdi mi?" Demenin güvenilir bir yolu yok. çünkü siz soruyu sorduktan sonra değiştirebilirler . Cevap üretilir üretilmez bayat .

Akla gelen beşinci soru şudur: API'yi kötü durumun önlenmesi için tasarlamanın bir yolu var mı?

Örneğin, "kaydet" işleminin iki adım gerektirmesini sağlayabilirsiniz. Birinci adım: değiştirilmekte olan kayıtta bir kilit elde edin. Bu işlem başarılı veya başarısız olur ve bir Boole döndürür. Arayan daha sonra başarısızlıkla nasıl başa çıkılacağına dair bir politika izleyebilir: bir süre bekleyin ve tekrar deneyin, vazgeçmeyin, ne olursa olsun. İkinci adım: kilit alındıktan sonra, kaydetme işlemini yapın ve kilidi açın. Artık tasarruf her zaman başarılı oluyor ve bu nedenle herhangi bir hata işleme konusunda endişelenmenize gerek yok. Eğer kaydetme başarısız olursa, bu gerçekten istisnai bir durumdur.


Hepsi çok iyi noktalar, teşekkürler. Şimdi işte muhtemelen yazımı özetleyen bir retorik soru: File.Open () 'ı yeniden tasarlayacak olsaydınız, bunun yerine bir File.TryOpen () yaratır mıydınız? Tüketiciye başarısızlığın nedenini nasıl iletirsiniz? Yoksa eksojen bir istisna atmak gerçekten buradaki en iyi uzlaşma mı?
Mike,

10
@Mike: Dosya sistemleri dış istisnaların kullanımına güzel bir örnektir. Nadiren başarısız olurlar, bu yüzden başarısızlık olağanüstüdür. Tahmin edilemeyen bir şekilde başarısız oluyorlar ve tamamen arayan kişinin kontrolü dışındaki nedenlerden dolayı (ethernet kablosunu takılı tutan bir "kilit" yok) var ve bu hatalar hem farklı hem de işlem yapılabilir (yani, çünkü bir hata. Bulunamadı vs dosya bulundu ancak yazma erişiminiz yok, farklı şekillerde işlem yapılabilir.) Bütün bunlar bir istisna olarak bir hatayı temsil etmek için sebepler.
Eric Lippert,

Şu anda cevaplanacak soruyu düşünüyorum, ancak merak ediyorum;) Eğer yöntem 2 veya daha fazla nedenden dolayı başarısız olursa, başarısızlıklar eyleme geçilemez, başarısızlıklar beklenmedik ve başarısızlıklar önceden tespit edilemez veya önlenemez. sen ne yapardın?
Mike,

@Mike Eric için konuşamam ama bu hata kodları için iyi bir yer gibi görünüyor. Belki de bir enum üyesi döndürmek.
Matthew

1

ValueAlreadyExists durum kolayca kontrol edilebilir eğer örnekte, bu olmalıdır kontrol edilmeli ve bir istisna Kaydet denemeden önce yükseltilmiş olması, bir deneyin bu durumda gerekli olmalıdır sanmıyorum. Yarış koşulunun vaktinden önce kontrol edilmesi daha zordur, bu yüzden bu durumda Kaydetmeyi Deneyin, muhtemelen çok iyi bir fikirdir.

Genel olarak, çok muhtemel olduğunu düşündüğüm bir durum varsa (örneğin NoDataReturned, DivideByZero, vb.) VEYA kontrol etmesi çok kolaydır (boş bir koleksiyon veya NULL değeri gibi), kontrol etmeye çalışıyorum Bir istisna yakalamak zorunda olduğum noktaya gelmeden önce vaktinden önce uğraşır ve onunla ilgilenirim. Kabul ediyorum ki, bu koşulları önceden bilmek her zaman kolay değildir, bazen kod yalnızca zorlu testler altındayken ortaya çıkarlar.


0

save()Yöntemi bir özel durum olmalıdır.

En üstteki katman , Unix benzeri bir komut satırı programları olmadıkça, programı sonlandırmadan , kullanıcıyı sonlandırmalı ve bilgilendirmelidir; bu durumda sonlandırılması uygundur.

İade değerleri istisnaları yönetmek için iyi bir yol değildir.

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.