Enum-state doğrulamasına karşı bir try-finally (catch olmadan) kullanma


9

Bu soruyla ilgili olarak, bir istisnanın mümkün olan en yüksek noktaya nasıl yakınlaştırılması gerektiği konusundaki tavsiyeleri okudum .

En iyi uygulamadaki ikilemim bir kişinin enum (veya değeri temsil eden bir int, hata için 0, tamam için 1, uyarı için 2 vb.) Duruma göre döndürmek için bir dene / yakala / son kullanması gerekip gerekmediğidir . bir cevap her zaman sırayladır, yoksa çağrılan bölümün onunla başa çıkması için istisnanın geçmesine izin verilmeli midir?

Toplayabildiğim kadarıyla, bu duruma bağlı olarak farklı olabilir, bu yüzden orijinal tavsiye garip görünüyor.

Örneğin, bir web hizmetinde, her zaman bir durum döndürmek istersiniz, bu nedenle herhangi bir istisna yerinde ele alınmalıdır, ancak http aracılığıyla bazı verileri gönderen / alan bir fonksiyonun içinde şunu söyleyelim: (örneğin 404 olması durumunda) sadece onu tetikleyene geçmek için istisna. Bunu yapmazsanız, sonucun niteliğini (hata: 404) ve sonucun kendisini bilgilendirmek için bir yol oluşturmanız gerekir.

Verileri alan / yayınlayan yardımcı fonksiyon içindeki 404 istisnasını yakalamak mümkün olsa da, öyle değil mi? Programdaki durumları belirtmek (ve elbette uygun şekilde belgelemek) için bir smallint kullanan ve daha sonra bu bilgiyi dışarıdaki akıl sağlığı doğrulama amaçları için (her şey tamam / hata işleme) kullanmak mı?

Güncelleme: Ana sınıflandırma için ölümcül / ölümcül olmayan bir istisna bekliyordum, ancak cevaplara halel getirmemek için bunu dahil etmek istemedim. Sorunun ne hakkında olduğunu açıklığa kavuşturalım: İstisnaları değil, atılan istisnaları ele almak. İstenen efekt nedir: Bir hata tespit edin ve ondan kurtarmaya çalışın. Kurtarma mümkün değilse, en anlamlı geri bildirimi sağlayın.

Yine, http get / post örneğinde, asıl arayan kişiye ne olduğunu açıklayan yeni bir nesne sağlamalısınız? Bu yardımcı kullandığınız bir kütüphanedeyse, işlem için bir durum kodu vermesini bekler misiniz, yoksa bir try-catch bloğuna dahil eder misiniz? Eğer tasarlıyorsanız , bir durum kodu verir misiniz veya bir istisna atar ve üst seviyenin bunu bir durum koduna / mesaja çevirmesine izin verir misiniz?

Özet: İstisna üretmek yerine bir kod parçası bir durum kodu döndürürse, bunun getirebileceği sonuçlarla birlikte nasıl seçersiniz?


1
Bu, kullanılan hata işleme biçimini değiştiren hatayla ilgilenmez. 404 vakasında geçmesine izin verecektiniz çünkü idare edemezsiniz.
stonemetal

"Bir değeri temsil eden bir int, hata için 0, tamam için 1, uyarı için 2 vb." Lütfen bunun manşet dışı bir örnek olduğunu söyleyin! Tamam'ı ifade etmek için 0 kullanmak kesinlikle standarttır ...
anaximander

Yanıtlar:


15

İstisnai durumlar için istisnalar kullanılmalıdır. Bir istisna atmak, temel olarak, "Bu durumu burada halledemiyorum; çağrı yığınında daha yüksek olan biri bunu benim için yakalayıp halledebilir mi?"

Arayanın bu değeri alacağı ve onunla anlamlı bir şey yapacağına açıksa, bir değer döndürmek tercih edilebilir. Bu, özellikle bir istisna atmanın performansla ilgili sonuçları varsa doğrudur, yani sıkı bir döngüde ortaya çıkabilir. Bir istisna atmak, bir değer döndürmekten çok daha uzun sürer (en az iki büyüklükte).

İstisnalar asla program mantığını uygulamak için kullanılmamalıdır. Başka bir deyişle, bir şeyi yapmak için bir istisna atmayın; bunun yapılamayacağını belirtmek için bir istisna atın.


Cevabınız için teşekkürler, en bilgilendirici ama odaklandığım istisna işleme ve istisna atma değil. 404 istisnasını alır almaz mı yoksa yığının üstüne çıkmasına izin vermeli misiniz?
Mihalis Bagos

Düzenlemenizi görüyorum, ancak cevabımı değiştirmiyor. Arayan için anlamlıysa istisnayı bir hata koduna dönüştürün. Değilse, istisnayı ele alın; yığının yukarı çıkmasına izin verin; veya yakalayın, onunla bir şeyler yapın (bir günlüğe veya başka bir şeye yazın gibi) ve yeniden düşünün.
Robert Harvey

1
+1: makul ve dengeli bir açıklama için. İstisnai durumları ele almak için bir istisna kullanılmalıdır. Aksi takdirde, bir işlev veya yöntem anlamlı bir değer (numaralandırma veya seçenek türü) döndürmeli ve arayan kişi bunu doğru şekilde işlemelidir. Belki fonksiyonel programlamada popüler olan üçüncü bir alternatiften bahsedilebilir, yani devam.
Giorgio

4

Bir keresinde okuduğum bazı iyi tavsiyeler, uğraştığınız verilerin durumu göz önüne alındığında ilerleyemediğiniz durumlarda istisnalar atmak, ancak bir istisna atabilecek bir yönteminiz varsa, verilerin mümkün olup olmadığını iddia etmek için mümkün olan bir yöntemi de sağlayın yöntem çağrılmadan önce geçerlidir.

Örneğin, sağlanan dosya yoksa System.IO.File.OpenRead () bir FileNotFoundException özel durumu oluşturur, ancak aynı zamanda daha önce çağırmanız gereken dosyanın mevcut olup olmadığını gösteren bir .Exists () yöntemi de sağlar. beklenmeyen istisnaları önlemek için OpenRead () çağrılır.

Sorunun "ne zaman bir istisna ile uğraşmalıyım" kısmına cevap vermek için, bu konuda gerçekten bir şeyler yapabileceğiniz her yerde söyleyebilirim. Yönteminiz, çağırdığı bir yöntem tarafından atılan bir istisna ile baş edemiyorsa, onu yakalamayın. Çağrı zincirini onunla başa çıkabilecek bir şeye yükseltmesine izin verin. Bazı durumlarda, bu yalnızca Application.UnhandledException öğesini dinleyen bir günlükçü olabilir.


Birçok kişi, özellikle de python programcıları EAFP'yi tercih eder, yani " İzin almaktan affetmek daha kolaydır"
Mark Booth

1
.Exists () ile olduğu gibi istisnalardan kaçınma hakkında yorum yapmak için +1.
codingoutloud

+1 Bu hala iyi bir tavsiye. Yazdığım / yönettiğim kodda, bir İstisna "Olağandışı" dır, bir geliştiricinin görmesi için 9/10 kez bir İstisna amaçlanmıştır, hey diyor ki, defensivley programlama olmalı! Diğer 1 kez, başa çıkamayacağımız bir şey ve bunu kaydedip elimizden gelenin en iyisini yapıyoruz. Tutarlılık önemlidir, örneğin, konvansiyonla normalde gerçek bir yanlış yanıt ve standart ücret / işleme için dahili mesajlarımız olacaktır. Her şey için istisnalar gibi görünen 3. taraf api'leri çağrıda ele alınabilir ve kabul edilen standart süreç kullanılarak iade edilebilir.
Gavin Howden

3

bir enum (veya değeri temsil eden bir int, hata için 0, tamam için 1, duruma göre 2 vb. için uyarı), döndürmek için bir try / catch / sonunda kullanın, böylece bir yanıt her zaman sırayla olur,

Bu korkunç bir tasarım. Sayısal bir koda çevirerek bir istisnayı "maskelemeyin". Düzgün, açık bir istisna olarak bırakın.

ya da çağrı yapan tarafın onunla başa çıkması için istisnanın geçmesine izin vermeli mi?

İstisnalar bunun için.

mümkün olduğunca yükseltildiği yere yakın

Hiç evrensel bir gerçek değil . Bazen iyi bir fikir. Diğer zamanlarda bu kadar yararlı değil.


Korkunç bir tasarım değil. Microsoft bunu birçok yerde, yani varsayılan asp.NET Üyelik sağlayıcısında uygular. Bunun dışında bu cevabın konuşmaya nasıl bir katkıda bulunduğunu göremiyorum
Mihalis Bagos

@MihalisBagos: Tek yapabileceğim, Microsoft'un yaklaşımının her programlama dili tarafından benimsenmediğini önermek. İstisnasız dillerde değer döndürmek önemlidir. C en dikkate değer örnektir. İstisnaları olan dillerde, hataları göstermek için "kod değerleri" döndürmek korkunç bir tasarımdır. Daha ifbasit istisna yönetimi yerine (bazen) hantal ifadelere yol açar . Cevap ("Nasıl seçilir?") Basittir. Yapma . Bence bu konuşmaya katılıyor. Ancak bu yanıtı göz ardı etmekte özgürsünüz.
S.Lott

Fikrinizin önemli olmadığını söylemiyorum ama fikrinizin gelişmediğini söylüyorum. Bu yorumla birlikte, bunun gerekçelerini istisnaları kullanabileceğimiz yerde yapmalıyız. Durum kodunu, kod akışı durumlarının kategorileştirilmesi / düzenlenmesi yerine maskeleme olarak görmüyorum
Mihalis Bagos

1
İstisna zaten bir kategorizasyon / kuruluştur. Kesin bir istisnayı, kolayca "normal" veya "istisnai olmayan" dönüş değerleriyle karıştırılabilen bir dönüş değeriyle değiştirirken değeri görmüyorum. Dönüş değerleri her zaman istisnai olmamalıdır . Bence çok gelişmiş değil: çok basit. Bir istisnayı sayısal bir koda dönüştürmeyin. Hayal edebileceğimiz tüm mükemmel kullanım örneklerini sunan mükemmel bir veri nesnesiydi.
S.Lott

3

S.Lott'a katılıyorum . İstisnayı kaynağa mümkün olduğunca yakın tutmak duruma bağlı olarak iyi bir fikir veya kötü bir fikir olabilir. İstisnaları ele almanın anahtarı, yalnızca bu konuda bir şeyler yapabileceğiniz zaman onları yakalamaktır. Bunları yakalamak ve arama işlevine sayısal bir değer döndürmek genellikle kötü bir tasarımdır. Sadece iyileşene kadar yüzmelerine izin vermek istiyorsun.

İstisna işlemeyi her zaman uygulama mantığımdan bir adım uzakta olarak görüyorum. Kendime soruyorum, bu istisna atılırsa, çağrı yığınım ne kadar desteklenmeli Uygulamam kurtarılabilir durumda olmadan önce taramak zorunda mıyım? Birçok durumda, uygulama içinde kurtarmak için yapabileceğim bir şey yoksa, bu üst seviyeye kadar onu yakalamıyorum ve sadece istisnayı günlüğe kaydeder, işi başarısız olur ve temiz bir şekilde kapatmaya çalışırım.

Onlarla ne yapacağınızı bilinceye kadar istisna işlemeyi ne zaman ve nasıl ayarlayacağınız konusunda gerçekten zor ve hızlı bir kural yoktur.


1

İstisnalar güzel şeylerdir. Gereksiz belirsizliğe başvurmadan çalışma süresi probleminin açık bir tanımını yapmanıza izin verir. İstisnalar yazılabilir, alt yazılabilir ve türe göre işlenebilir. Başka bir yerde işlemek için etrafından geçebilirler ve ele alınamazlarsa, uygulamanızdaki daha yüksek bir katmanda ele alınmak üzere yeniden yükseltilebilirler. Ayrıca, gizlenmiş hata kodlarıyla başa çıkmak için çok sayıda çılgın mantık çağırmaya gerek kalmadan otomatik olarak yönteminizden dönecektir.

Kodunuzda geçersiz verilerle karşılaştıktan hemen sonra bir istisna atmalısınız. Atılabilecek istisnaları işlemek için diğer yöntemlere çağrıları try..catch..final olarak sarmalısınız ve herhangi bir istisnaya nasıl yanıt vereceğinizi bilmiyorsanız, daha yüksek katmanlara göstermek için tekrar atarsınız. başka bir yerde ele alınması gereken yanlış bir şey var.

Hata kodlarını yönetmek çok zor olabilir. Genellikle kodunuzda çok fazla gereksiz çoğaltma ve / veya hata durumlarıyla başa çıkmak için çok sayıda dağınık mantık ortaya çıkar. Kodun kendisi anlamlı olmayacağından ve kullanıcıya hata için bir bağlam sağlamadığından, kullanıcı olmak ve bir hata koduyla karşılaşmak daha da kötüdür. Öte yandan, bir istisna kullanıcıya "bir değer girmeyi unuttun" veya "geçersiz bir değer girdiniz, kullanabileceğiniz geçerli aralık ..." veya "Kullanmıyorum ne olduğunu biliyorum, teknik desteğe başvurun ve onlara sadece çöktüğümü söyleyin ve onlara aşağıdaki yığın izlemesini verin ... ".

OP benim sorudur Neden yeryüzünde size olur DEĞİL hata kodları dönen üzerinde istisnaları kullanmak istiyor?


0

Tüm iyi cevaplar. Ben de bir istisna atmak yerine bir hata kodu döndürme arayan kodunu daha karmaşık hale getirebilir eklemek istiyorum. Söyle yöntemi A yöntemi B'yi çağırır, C yöntemini çağırır ve C bir hatayla karşılaşır. C bir hata kodu döndürürse, şimdi B'nin bu hata kodunu işleyip işleyemeyeceğini belirlemek için mantığı olmalıdır. Olamazsa, A'ya geri döndürmesi gerekir. A, hatayı işleyemezse ne yaparsınız? İstisna atmak mı? Bu örnekte, C sadece bir istisna atarsa ​​kod çok daha temizdir, B istisnayı yakalamaz, böylece ekstra kod gerekmeden otomatik olarak iptal edilir ve A, başkalarının aramaya devam etmesine izin verirken belirli istisna türlerini yakalayabilir yığını.

Bu, aşağıdakileri kodlamak için iyi bir kural getirir:

Kod satırları altın mermiler gibidir. İşi yapmak için mümkün olduğunca az kullanmak istiyorsunuz.


0

Her iki çözümün bir kombinasyonunu kullandım: her doğrulama işlevi için, doğrulama durumu (bir hata kodu) ile doldurduğum bir kaydı geçiyorum. Fonksiyonun sonunda, bir doğrulama hatası varsa, bir istisna atarım, bu şekilde her alan için bir istisna atmazım, sadece bir kez.

Ayrıca, veri geçersiz olduğunda yürütmenin devam etmesini istemediğim için, bir istisna atmanın yürütmeyi durduracağından da yararlandım.

Örneğin

procedure Validate(var R:TValidationRecord);
begin
  if Field1 is not valid then
  begin
    R.Field1ErrorCode=SomeErrorCode;
    ErrorFlag := True; 
  end; 
  if Field2 is not valid then
  begin
    R.Field2ErrorCode=SomeErrorCode;
    ErrorFlag := True; 
  end;
  if Field3 is not valid then
  begin
    R.Field3ErrorCode=SomeErrorCode;
    ErrorFlag := True; 
  end;

  if ErrorFlag then
    ThrowException
end;

Yalnızca boole'ye güveniyorsanız, işlevimi kullanan geliştirici bunu dikkate almalıdır:

if not Validate() then
  DoNotContinue();

ama unutup sadece arayabilir Validate()(bilmemesi gerektiğini biliyorum, belki de yapabilir).

Yani, yukarıdaki kodda iki avantaj kazandım:

  1. Doğrulama işlevinde yalnızca bir istisna.
  2. İstisna, yakalanmamış olsa bile, yürütmeyi durduracak ve test zamanında görünecektir

0

Burada bir cevap yok - bir çeşit HttpException yok gibi.

4xx veya 5xx yanıtı aldıklarında, temeldeki HTTP kitaplıklarının bir istisna oluşturması çok mantıklıdır; en son HTTP özelliklerine baktığımda bu hatalardı.

Bu istisnayı atmak - ya da sarmak ve yeniden yazmak - bunun gerçekten bir kullanım meselesi olduğunu düşünüyorum. Örneğin, API'dan bazı verileri almak ve uygulamalara göstermek için bir sarıcı yazıyorsanız, anlamsal olarak bir HTTP 404 döndüren varolmayan bir kaynak talebinin bunu yakalamak ve null döndürmek için daha anlamlı olacağına karar verebilirsiniz. Öte yandan bir 406 hatası (kabul edilemez) bir hata atmaya değer olabilir, çünkü bir şey değişti ve uygulama çöküyor ve yardım için çığlık atıyor olmalı.

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.