Hata Ayıkla.Assert - Exception Throwing


94

İddiaların nasıl ve ne zaman kullanılacağına dair çok sayıda makale (ve StackOverflow'da yayınlanan birkaç benzer soru) okudum ve onları iyi anladım. Ama yine de, Debug.Assertbasit bir istisna atmak yerine beni ne tür bir motivasyon kullanmaya itmesi gerektiğini anlamıyorum . Demek istediğim, .NET'te başarısız bir iddiaya verilen varsayılan yanıt "dünyayı durdurmak" ve kullanıcıya bir mesaj kutusu göstermektir. Bu tür bir davranış değiştirilebilir olsa da, bunu yapmak için oldukça can sıkıcı ve gereksiz buluyorum, bunun yerine uygun bir istisna atabilirim. Bu şekilde, istisnayı atmadan hemen önce hatayı uygulamanın günlüğüne kolayca yazabilirim ve ayrıca uygulamamın donması gerekmez.

Öyleyse neden Debug.Assertbasit bir istisna yerine kullanmalıyım ? Olmaması gereken bir yere bir iddia yerleştirmek sadece her türlü "istenmeyen davranışa" neden olabilir, bu yüzden benim bakış açıma göre, bir istisna atmak yerine bir iddia kullanarak gerçekten hiçbir şey kazanmıyorum. Bana katılıyor musun yoksa burada bir şey mi eksik?

Not: "Teoride" farkın ne olduğunu tam olarak anlıyorum (Hata Ayıklama ve Yayınlama, kullanım kalıpları vb.), Ancak gördüğüm kadarıyla, bir iddia yapmak yerine bir istisna atmam daha iyi olur. Bir üretim sürümünde bir hata keşfedilirse, yine de "iddia" nın başarısız olmasını isterim (sonuçta, "ek yük" gülünç derecede küçüktür), bu yüzden bunun yerine bir istisna atmam daha iyi olur.


Düzenleme: Gördüğüm gibi, bir iddia başarısız olursa, bu, uygulamanın bir tür bozuk, beklenmedik duruma girdiği anlamına gelir. Öyleyse neden idama devam etmek isteyeyim? Uygulamanın bir hata ayıklama veya yayın sürümünde çalışıp çalışmadığı önemli değildir. Aynı şey ikisi için de geçerli


1
"Bir üretim sürümünde bir hata keşfedilirse, yine de" iddianın "başarısız olacağını" söylediğiniz şeyler için, kullanmanız gerekenler istisnalardır
Tom Neyland

1
Performans tek nedendir. Her şeyi her zaman geçersiz kılmak hızı düşürebilir, ancak tamamen farkedilemez olabilir. Bu, esas olarak asla gerçekleşmemesi gereken durumlar içindir, örneğin, önceki bir işlevde onu zaten boş olarak kontrol ettiğinizi biliyorsunuz, tekrar kontrol ederek döngüleri boşa harcamanın bir anlamı yok. Debug.assert, sizi bilgilendirmek için son şans birim testi görevi görür.
rulolar

Yanıtlar:


178

Muhakemenizin makul olduğunu kabul etsem de - yani, bir iddia beklenmedik bir şekilde ihlal edilirse, fırlatarak yürütmeyi durdurmak mantıklıdır - şahsen iddialar yerine istisnaları kullanmam. İşte nedeni:

Başkalarının da söylediği gibi, iddialar imkansız olan durumları belgelemelidir , öyle ki imkansız olduğu iddia edilen durum oluşursa geliştirici bilgilendirilir. Buna karşılık istisnalar, istisnai, olası olmayan veya hatalı durumlar için bir kontrol akışı mekanizması sağlar, ancak imkansız durumlar için değildir. Benim için en önemli fark şudur:

  • HER ZAMAN, belirli bir atış ifadesini uygulayan bir test senaryosu oluşturmak mümkün olmalıdır. Böyle bir test senaryosu oluşturmak mümkün değilse, programınızda asla çalışmayan bir kod yolunuz vardır ve bu, ölü kod olarak kaldırılmalıdır.

  • Bir iddianın ateşlenmesine neden olan bir test senaryosu üretmek ASLA mümkün olmamalıdır. Bir iddia patlarsa, ya kod yanlıştır ya da iddia yanlıştır; her iki durumda da kodda bir şeyin değişmesi gerekir.

Bu yüzden bir iddiayı bir istisna ile değiştirmem. İddia gerçekten çalışamazsa, onu bir istisna ile değiştirmek, programınızda test edilemeyen bir kod yoluna sahip olduğunuz anlamına gelir . Test edilemeyen kod yollarından hoşlanmıyorum.


16
İddialarla ilgili sorun, üretim yapısında orada olmamalarıdır. Varsayılan bir koşulun başarısız olması, programınızın tanımlanmamış davranış alanına girdiği anlamına gelir, bu durumda sorumlu bir programın yürütmeyi mümkün olan en kısa sürede durdurması gerekir (yığının çözülmesi, ne kadar titiz olmak istediğinize bağlı olarak biraz tehlikelidir). Evet, iddiaların ateşlenmesi genellikle imkansız olmalı , ancak işler vahşi doğduğunda neyin mümkün olduğunu bilmiyorsunuz. Eğer olarak düşünülebilir Ne imkansız kudreti üretiminde olur ve sorumlu bir programdır ihlal varsayımları algılar ve derhal harekete geçmelidir.
kizzx2

2
@ kizzx2: Peki, üretim kodu başına kaç tane imkansız istisna yazıyorsunuz?
Eric Lippert

4
@ kixxx2: Bunu Bu, C # olabilir Trace.Assert kullanarak üretim kodunda iddialarını tutun. Son kullanıcıya kaba davranmak yerine, üretim onaylarını bir metin dosyasına yeniden yönlendirmek için app.config dosyasını bile kullanabilirsiniz.
HTTP 410

3
@AnorZaken: Düşünceniz, istisnalardaki bir tasarım hatasını gösteriyor. Başka bir yerde de belirttiğim gibi, istisnalar (1) ölümcül felaketler, (2) asla olmaması gereken kafasız hatalar, (3) istisnai olmayan bir durumu işaret etmek için bir istisnanın kullanıldığı tasarım hataları veya (4) beklenmedik dışsal koşullar. . Neden bu tamamen farklı dört şeyin tümü istisnalarla temsil ediliyor? Benim druthers olsaydı, boneheaded istisnalar catchable olmaz "boş duruma gelmiş olan" hiç . Bu var asla doğru ve gerektiği daha zarar vermeden programınızı sonlandırmak . Daha çok iddia gibi olmalılar.
Eric Lippert

2
@Backwards_Dave: Yanlış iddialar kötüdür, doğru değil. Onaylar, üretimde çalıştırmak istemeyeceğiniz pahalı doğrulama kontrolleri yapmanızı sağlar. Ve üretimde bir iddia ihlal edilirse, son kullanıcı bu konuda ne yapmalıdır?
Eric Lippert

17

İddialar, programcının dünyayı anlamasını kontrol etmek için kullanılır. Bir iddia, ancak programcı yanlış bir şey yaptıysa başarısız olmalıdır. Örneğin, kullanıcı girişini kontrol etmek için asla bir onaylama kullanmayın.

"Gerçekleşemeyen" koşulları test eder. İstisnalar, "olmaması gereken ama olması gereken" koşullar içindir.

İddialar yararlıdır çünkü derleme zamanında (hatta çalışma zamanında) davranışlarını değiştirebilirsiniz. Örneğin, genellikle sürüm yapılarında, gereksiz ek yük getirdikleri için iddialar kontrol bile edilmez. Bu aynı zamanda dikkatli olunması gereken bir konudur: testleriniz uygulanmayabilir bile.

İddialar yerine istisnalar kullanırsanız bir miktar değer kaybedersiniz:

  1. Kod daha ayrıntılıdır, çünkü bir istisnayı test etmek ve atmak en az iki satırdır, oysa bir iddia yalnızca bir satırdır.

  2. Test ve atış kodunuz her zaman çalışır, iddialar ise derlenebilir.

  3. Diğer geliştiricilerle iletişiminizi kaybedersiniz çünkü iddiaların, kontrol eden ve atan ürün kodundan farklı bir anlamı vardır. Gerçekten bir programlama iddiasını test ediyorsanız, bir iddia kullanın.

Daha fazla bilgi için: http://nedbatchelder.com/text/assert.html


Eğer "gerçekleşemezse", o zaman neden bir iddia yazın. Bu gereksiz değil mi? Eğer gerçekten olabilir ama olmamalıysa, bu, istisnalar için "olmamalı ama yapmalı" ile aynı şey değil mi?
David Klempfner

2
Bir nedenden ötürü tırnak içinde "olamaz" ifadesi yer almaktadır: Bu, yalnızca programcı programın başka bir bölümünde yanlış bir şey yaptıysa olabilir. İddia, programcı hatalarına karşı bir kontroldür.
Ned Batchelder

@NedBatchelder Programcı terimi , bir kitaplık geliştirdiğinizde biraz belirsizdir. Bu "imkansız durumların" kütüphane kullanıcısı tarafından imkansız olması gerektiği , ancak kütüphane yazarının bir hata yapması durumunda mümkün olabileceği doğru mudur?
Bruno Zell

12

DÜZENLEME: Gönderinizde yaptığınız düzenlemeye / nota yanıt olarak: Başarmaya çalıştığınız şeylerin türü için iddiaları kullanmak yerine istisnaları kullanmak doğru şey gibi görünüyor. Bence çarptığınız zihinsel engel, aynı amacı gerçekleştirmek için istisnalar ve iddialar düşünmeniz ve bu nedenle hangisinin kullanmanın 'doğru' olacağını anlamaya çalışmanızdır. İddiaların ve istisnaların nasıl kullanılabileceği konusunda bazı örtüşmeler olsa da, aynı soruna farklı çözümler oldukları konusunda kafa karıştırmayın - öyle değiller. İddiaların ve İstisnaların her birinin kendi amacı, güçlü ve zayıf yönleri vardır.

Kendi sözlerimle bir cevap yazacaktım ama bu konsept benim sahip olacağımdan daha iyi bir adalet sağlıyor:

C # Station: Onaylar

Assert ifadelerinin kullanımı, çalışma zamanında program mantığı hatalarını yakalamak için etkili bir yol olabilir ve yine de üretim kodundan kolayca filtrelenebilir. Geliştirme tamamlandıktan sonra, kodlama hataları için bu fazlalık testlerin çalışma zamanı maliyeti, derleme sırasında önişlemci sembolü NDEBUG [tüm iddiaları devre dışı bırakır] tanımlanarak ortadan kaldırılabilir. Bununla birlikte, iddianın kendisine yerleştirilen kodun üretim sürümünde çıkarılacağını unutmayın.

Bir iddia, yalnızca aşağıdakilerin tümü geçerli olduğunda bir koşulu test etmek için en iyi şekilde kullanılır:

* the condition should never be false if the code is correct,
* the condition is not so trivial so as to obviously be always true, and
* the condition is in some sense internal to a body of software.

Yazılımın normal çalışması sırasında ortaya çıkan durumları tespit etmek için neredeyse hiçbir zaman iddialar kullanılmamalıdır. Örneğin, genellikle bir kullanıcının girdisindeki hataları kontrol etmek için iddialar kullanılmamalıdır. Bununla birlikte, arayanın bir kullanıcının girişini zaten kontrol ettiğini doğrulamak için iddiaları kullanmak mantıklı olabilir.

Temel olarak, bir üretim uygulamasında yakalanması / ele alınması gereken şeyler için istisnalar kullanın, geliştirme için yararlı olacak ancak üretimde kapatılacak mantıksal kontroller yapmak için iddiaları kullanın.


Tüm bunların farkındayım. Ama mesele şu ki, kalın olarak işaretlediğiniz aynı ifade istisnalara da gider. Yani benim gördüğüm şekliyle, bir iddia yerine, sadece bir istisna atabilirim (çünkü konuşlandırılmış bir sürümde "asla gerçekleşmemesi gereken durum" meydana gelirse, yine de bundan haberdar olmak isterim [artı, uygulama bozuk bir duruma girebilir, bu nedenle bir istisna uygundur, normal yürütme akışına devam etmek istemeyebilirim)

1
Değişmezler üzerinde iddialar kullanılmalıdır; istisnalar, diyelim ki bir şeyin boş olmaması gerektiğinde kullanılmalıdır, ancak bu (bir yöntemin parametresi gibi) olacaktır.
Ed S.

Sanırım her şey ne kadar savunma yapmak istediğinize bağlı.
Ned Batchelder

Katılıyorum, ihtiyacın olan şey için istisnalar gitmenin yolu. İstediğinizi söylediniz: Üretimde tespit edilen arızalar, hatalarla ilgili bilgileri günlüğe kaydetme yeteneği ve yürütme akış kontrolü, vb. Bu üç şey, bana yapmanız gereken şeyin bazı istisnaları atmak olduğunu düşündürüyor.
Tom Neyland

7

Bence (yapmacık) pratik bir örnek, farkı aydınlatmaya yardımcı olabilir:

( MoreLinq'in Batch uzantısından uyarlanmıştır )

// 'public facing' method
public int DoSomething(List<string> stuff, object doohickey, int limit) {

    // validate user input and report problems externally with exceptions

    if(stuff == null) throw new ArgumentNullException("stuff");
    if(doohickey == null) throw new ArgumentNullException("doohickey");
    if(limit <= 0) throw new ArgumentOutOfRangeException("limit", limit, "Should be > 0");

    return DoSomethingImpl(stuff, doohickey, limit);
}

// 'developer only' method
private static int DoSomethingImpl(List<string> stuff, object doohickey, int limit) {

    // validate input that should only come from other programming methods
    // which we have control over (e.g. we already validated user input in
    // the calling method above), so anything using this method shouldn't
    // need to report problems externally, and compilation mode can remove
    // this "unnecessary" check from production

    Debug.Assert(stuff != null);
    Debug.Assert(doohickey != null);
    Debug.Assert(limit > 0);

    /* now do the actual work... */
}

Yani olarak Eric Lippert ve ark söylediler, sadece doğru olmasını bekliyoruz bu şeyler assert, her ihtimale karşı sen (geliştirici) kazayla yanlış kullanmış kodunuzu çözebilmek için, başka bir yerde. Temelde, neyin geleceğini kontrol edemediğinizde veya önceden tahmin edemediğinizde istisnalar atarsınız, örneğin kullanıcı girdisi için , böylece kötü veriyi veren her ne ise uygun şekilde yanıt verebilir (örn. Kullanıcı).


3 Onayınız tamamen gereksiz değil mi? Parametrelerinin yanlış olarak değerlendirilmesi imkansızdır.
David Klempfner

1
Asıl nokta bu - iddialar imkansız olan şeyleri belgelemek için var. Neden bunu yapasın ki? Çünkü DoSomethingImpl metodu içinde sizi uyaran ReSharper gibi bir şeye sahip olabilirsiniz, "burada boş referansı kaldırıyor olabilirsiniz" ve ona "Ne yaptığımı biliyorum, bu asla boş olamaz" demek istersiniz. Bu aynı zamanda, DoSomething ve DoSomethingImpl arasındaki bağlantıyı hemen fark edemeyebilecek daha sonraki programcılar için de bir göstergedir, özellikle birbirinden yüzlerce satır ayrıysa.
Marcel Popescu

4

Code Complete'den başka bir külçe :

"İddia, bir varsayım doğru değilse yüksek sesle şikayet eden bir işlev veya makrodur. Kodda yapılan varsayımları belgelemek ve beklenmedik durumları temizlemek için iddiaları kullanın. ...

"Geliştirme sırasında, iddialar çelişkili varsayımları, beklenmedik koşulları, rutinlere aktarılan kötü değerleri vb. Ortadan kaldırır."

Neyin ileri sürülmesi ve belirtilmemesi gerektiğine dair bazı yönergeler eklemeye devam ediyor.

Öte yandan istisnalar:

"Beklenmedik durumlara dikkat çekmek için istisna işlemeyi kullanın. İstisnai durumlar, geliştirme sırasında açık ve üretim kodu çalışırken kurtarılabilir olacak şekilde ele alınmalıdır."

Bu kitaba sahip değilseniz satın almalısınız.


2
Kitabı okudum, mükemmel. Ancak .. sorumu cevaplamadınız :)

Haklısın cevap vermedim. Cevaplarım hayır, sana katılmıyorum. İddialar ve İstisnalar, yukarıda ele alındığı gibi farklı hayvanlardır ve diğerlerinin bir kısmı burada yayınlanmıştır.
Andrew Cowenhoven

0

Debug.Assert varsayılan olarak yalnızca hata ayıklama yapılarında çalışacaktır, bu nedenle sürüm yapılarınızda herhangi bir kötü beklenmeyen davranışı yakalamak istiyorsanız, proje özelliklerinizde istisnaları kullanmanız veya hata ayıklama sabitini açmanız gerekir ( genel olarak iyi bir fikir olmamak).


ilk kısmi cümle doğrudur, geri kalanı genel olarak kötü bir fikirdir: iddialar varsayımlardır ve doğrulama yoktur (yukarıda belirtildiği gibi), sürümde hata ayıklamayı etkinleştirmek gerçekten bir seçenek değildir.
Marc Wittke

0

Şeyler için kullanın iddialar OLAN mümkün ama olmamalı (bir onaylama koymak neden bu mümkün olmazsa,?).

Kulağa bir dava gibi gelmiyor mu Exception? Neden bir iddia yerine bir iddia kullanasınız Exception?

Çünkü, iddianızın parametresinin yanlış olmasını durduracak, iddianızdan önce çağrılan bir kod olmalıdır.

Genellikle Exceptionatılmayacağını garanti etmeden önce hiçbir kod yoktur .

Debug.Assert()Üretimde derlenen neden iyidir ? Hata ayıklamada bunun hakkında bilgi edinmek istiyorsanız, üretimde bunu bilmek istemez miydiniz?

Bunu yalnızca geliştirme sırasında istersiniz, çünkü bir kez Debug.Assert(false)durum bulduğunuzda , Debug.Assert(false)bunun bir daha olmayacağını garanti etmek için kod yazarsınız . Geliştirme tamamlandıktan sonra, Debug.Assert(false)durumları bulduğunuzu ve düzelttiğinizi varsayarak Debug.Assert(), artık gereksiz oldukları için güvenli bir şekilde derlenebilirler.


0

Oldukça büyük bir ekibin üyesi olduğunuzu ve sınıflar üzerinde örtüşme dahil olmak üzere aynı genel kod tabanında çalışan birkaç kişi olduğunu varsayalım. Diğer birkaç yöntemle çağrılan bir yöntem yaratabilirsiniz ve kilit çekişmesini önlemek için ona ayrı bir kilit eklemeyin, bunun yerine arama yöntemi tarafından önceden belirli bir kilitle kilitlendiğini "varsayarsınız". Debug.Assert (RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld) gibi; Diğer geliştiriciler, çağırma yönteminin kilidi kullanması gerektiğini söyleyen bir yorumu gözden kaçırabilir, ancak bunu göz ardı edemezler.

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.