Ne zaman Debug.Assert () kullanmalıyım?


220

CS derecesini bitirdikten sonra yaklaşık bir yıldır profesyonel bir yazılım mühendisiyim. C ++ ve C'de bir süredir iddiaları biliyordum, ancak yakın zamana kadar C # ve .NET'te var olduklarına dair hiçbir fikrim yoktu.

Üretim kodumuz hiçbir şey içermiyor ve sorum şu ...

Üretim kodumuzda Asserts kullanmaya başlamalı mıyım? Ve eğer öyleyse, ne zaman kullanımı en uygun? Bunu yapmak daha anlamlı olur mu

Debug.Assert(val != null);

veya

if ( val == null )
    throw new exception();

2
Ayarladığınız ikilik ipucu. Bu, ya - ya da istisnalar ve iddialar için, hem - hem de savunma kodu için bir sorun değildir. Ne zaman yapmalı bunu anlamaya çalışıyorsun.
Casper Leon Nielsen

5
Bir keresinde birisinin, bir istisna veya başka bir çökme yönteminin "Bundan anlamlı bir şekilde kurtulamamın hiçbir yolu olmadığı" ve buna ek olarak bir iddia, "Bu asla, asla gerçekleşmemeli" koşullar için uygun olduğunu önerdi. Fakat hangi gerçekçi koşullar, ilkini de tatmin etmeden ikinci koşulları tatmin eder? Üretimde kaldığı iddia edilen bir Python geçmişinden geldiğimde, Java / C # yaklaşımını üretimdeki bazı doğrulama işlemlerinizi devre dışı bırakmayı hiç anlamadım. Gerçekten görebildiğim tek durum doğrulama pahalı olup olmadığıdır.
Mark Amery


2
Şahsen ben kamusal yöntemler için istisnalar, özel yöntemler için iddialar kullanıyorum.
Fred

Yanıtlar:


230

Gelen Hata ayıklama Microsoft .NET 2.0 Uygulamalar John Robbins iddiaların üzerinde büyük bir bölüm vardır. Ana noktaları:

  1. Liberal olarak iddia edin. Asla çok fazla iddiada bulunamazsınız.
  2. İddialar istisnaların yerini almaz. İstisnalar, kodunuzun talep ettiği şeyleri kapsar; iddialar varsaydığı şeyleri kapsar.
  3. İyi yazılmış bir iddia size ne olduğunu ve nerede olduğunu (istisna gibi) değil, nedenini de söyleyebilir.
  4. Hataya neden olan içeriği yeniden oluşturmak için kod boyunca geriye doğru çalışmanızı gerektiren bir istisna mesajı genellikle şifrelenebilir. Bir iddia, hatanın oluştuğu tarihte programın durumunu koruyabilir.
  5. İddialar dokümantasyon olarak iki katına çıkar ve diğer geliştiricilere kodunuzun hangi varsayımlara bağlı olduğunu söyler.
  6. Bir onaylama başarısız olduğunda görüntülenen iletişim kutusu, işleme bir hata ayıklayıcı eklemenize olanak tanır, böylece yığının etrafına kesme noktası koyduğunuz gibi poke edebilirsiniz.

Not: Code Complete'i beğendiyseniz, bu kitabı takip etmenizi öneririz. WinDBG ve döküm dosyalarını kullanma hakkında bilgi edinmek için satın aldım, ancak ilk yarı hataları önlemek için ipuçları ile doludur.


3
Kısa ve yardımcı özet için +1. Çok doğrudan uygulanabilir. Benim için eksik olan ana şey, Trace.Assert ve Trace.Assert'in ne zaman kullanılacağıdır. Bunları ne zaman yaptığınız / üretim kodunuzda istemediğiniz hakkında bir şey.
Jon Coombs

2
JonCoombs "Trace.Assert vs. Trace.Assert" bir yazım hatası mı?
thelem

1
@thelem Jon belki de Debug.Assertvs. demekti Trace.Assert. İkincisi, bir Release derlemesinde ve bir Debug derlemesinde yürütülür.
DavidRR

Neden Debug.Assert'i istisna atmayı tercih etmeliyim?
Barış Akkurt

86

Debug.Assert()Değişmezleri sağlamak için sağlık kontrolleri yapmak istediğiniz kodu her yere koyun . Bir Release derlemesini derlediğinizde (yani DEBUGderleyici sabiti yok ), çağrılar Debug.Assert()kaldırılır, böylece performansı etkilemezler.

Aramadan önce yine de istisnalar atmalısınız Debug.Assert(). Bu iddia sadece siz gelişirken her şeyin beklendiği gibi olmasını sağlar.


35
Hala aramadan önce bir istisna atarsanız neden bir iddiada bulunduğunuzu açıklayabilir misiniz? Yoksa cevabını yanlış mı anladım?
Roman Starkov

2
@romkyns Bunları yine de eklemelisiniz, çünkü projenizi Yayınlama modunda oluşturduğunuzda, tüm doğrulama / hata denetimi kaldırılacaktır.
Oscar Mederos

28
@Oscar bunun ilk başta iddiaları kullanmanın bütün mesele olduğunu düşündüm ... Tamam o zaman, o zaman istisnaları önlerine koydun - o zaman neden iddiaları ortaya koydun?
Roman Starkov

4
@superjos: Katılmıyorum: MacLeod'un cevabındaki 2 numaralı nokta, gerçekten iddianıza ve istisnalara ihtiyacınız olduğunu, ancak aynı yerde olmadığını belirtir. Bir NullRefEx'i bir değişkene atmak işe yaramaz ve hemen ardından bir Assert yapın (assert yöntemi asla bu durumda, tüm iddianın noktası olan bir iletişim kutusu göstermez). MacLeod'un anlamı, bazı yerlerde bir istisnaya ihtiyacınız olacak, diğerlerinde bir Assert yeterli olacaktır.
David

1
Eğer her ikisi de gerekir ve olmalıdır: Bu sizinle başkasının Neyse cevap :) I benim yorumunu yorumlamaya pis bir hale gelebilir değil istisna koydu önce assert. "Aynı yerde değil" anlamından emin değilim. Yine, yorumlamayı reddediyorum, sadece düşüncelerimi / tercihlerimi belirteceğim: bazı işlemler başlamadan önce önkoşulları kontrol etmek veya işlemden sonra postcondcond'ları kontrol etmek için bir veya daha fazla varsayım koyun. Eklerin yanı sıra ve yine de, bir şeylerin yanlış gittiğini ve istisnalar atması gerekip gerekmediğini kontrol edin.
superjos

52

Gönderen Kod tam

8 Savunma Programlama

8.2 Bildiriler

Bir iddia, geliştirme sırasında kullanılan bir koddur - genellikle bir program veya makro - bir program çalışırken kendini kontrol etmesini sağlar. Bir iddia doğru olduğunda, bu her şeyin beklendiği gibi çalıştığı anlamına gelir. Yanlış olduğunda, kodda beklenmedik bir hata tespit ettiği anlamına gelir. Örneğin, sistem bir müşteri bilgi dosyasının hiçbir zaman 50.000'den fazla kayda sahip olmayacağını varsayarsa, program kayıt sayısının lezbiyen veya 50.000'e eşit olduğunu iddia edebilir. Kayıt sayısı 50.000'den az veya eşit olduğu sürece, iddia sessiz olacaktır. Bununla birlikte, 50.000'den fazla kayıtla karşılaşırsa, programda bir hata olduğunu yüksek sesle "iddia eder".

İddialar özellikle büyük, karmaşık programlarda ve yüksek güvenilirlik programlarında kullanışlıdır. Programcıların uyumsuz arabirim varsayımlarını, kod değiştirildiğinde hata veren hataları vb. Daha hızlı bir şekilde temizlemelerini sağlar.

Bir iddia genellikle iki argüman alır: doğru olması gereken varsayımı tanımlayan bir boole ifadesi ve eğer değilse görüntülenecek bir mesaj.

(...)

Normalde, kullanıcıların üretim kodunda onaylama mesajlarını görmesini istemezsiniz; iddialar öncelikle geliştirme ve bakım sırasında kullanım içindir. İddialar normalde geliştirme sırasında koda derlenir ve üretim kodundan derlenir. Geliştirme sırasında, iddialar çelişkili varsayımları, beklenmedik koşulları, rutinlere aktarılan kötü değerleri vb. Temizler. Üretim sırasında, iddialar sistem performansını düşürmemek için koddan derlenirler.


7
Peki, üretimde karşılaşılan bir müşteri bilgi dosyası 50.000'den fazla kayıt içeriyorsa ne olur? İddia üretim kodundan derlenmişse ve bu durum başka türlü ele alınmıyorsa, bu yazım sorunu yaşamıyor mu?
DavidRR

1
@DavidRR Evet, gerçekten. Ancak üretim bir sorun sinyalini verir vermez ve bazı geliştiriciler (bu kodu iyi bilmeyebilirler) sorunu ayıklarlarsa, iddia başarısız olur ve geliştirici sistemin istendiği gibi kullanılmadığını hemen bilir.
Marc

48

FWIW ... Genel yöntemlerimin if () { throw; }, yöntemin doğru bir şekilde çağrıldığından emin olmak için kalıbı kullanma eğiliminde olduğunu düşünüyorum. Özel yöntemlerim kullanma eğilimindedir Debug.Assert().

Fikir şu ki, özel yöntemlerimle kontrol altındayım, bu yüzden yanlış parametrelerle kendi özel yöntemlerimden birini çağırmaya başlarsam, o zaman bir yerde kendi varsayımımı kırdım - asla kazanmamalıydım bu duruma. Üretimde, bu özel iddialar, iç durumumu geçerli ve tutarlı tutmam gerektiğinden, ideal olarak gereksiz bir çalışma olmalıdır. Çalışma zamanında herkes tarafından çağrılabilen genel yöntemlere verilen parametrelerle kontrast: Hala istisnalar atarak parametre kısıtlamalarını zorunlu kılmam gerekiyor.

Ayrıca, çalışma sırasında bir şey çalışmazsa (ağ hatası, veri erişim hatası, üçüncü taraf hizmetinden alınan kötü veriler vb.) Özel yöntemlerim yine de istisnalar atabilir. Benim iddialarım sadece nesnenin durumu ile ilgili kendi iç varsayımları kırık değil emin olmak için vardır.


3
Bu, iyi bir uygulamanın çok açık bir açıklamasıdır ve sorulan soruya çok makul bir cevap vermektedir.
Casper Leon Nielsen

42

Çevresel varsayımları kontrol etmek için geliştirici varsayımlarını ve istisnaları kontrol etmek için ekleri kullanın.


31

Ben olsaydım yapardım:

Debug.Assert(val != null);
if ( val == null )
    throw new exception();

Veya tekrarlanan durum kontrolünden kaçınmak için

if ( val == null )
{
    Debug.Assert(false,"breakpoint if val== null");
    throw new exception();
}

5
Bu sorunu nasıl çözüyor? Bununla debug.assert anlamsız hale gelir.
Quibblesome

43
Hayır değil - istisna atılmadan hemen önce kod içine girer. Kodunuzda başka bir yerde bir deneme / yakalama varsa, istisna bile fark etmeyebilirsiniz!
Mark Ingram

2
+1 İnsanların hiçbir şey yapmadan sadece istisnaları denemeleri için çok fazla sorun
yaşadım

5
Sanırım bunu yapmak isteyebileceğiniz durumlar var, ama asla genel bir istisna yakalamamalısınız!
Casebash

8
@ Cevabınız için -1Ingram -1 ve haklı yorumunuzu + 1'leyin. Bu, bazı tuhaf durumlar için güzel bir hile, ancak tüm doğrulama için genel olarak yapılacak tuhaf bir şey gibi görünüyor.
Mark Amery

24

Üretim kodunuzda (örn. Release derlemeleri) Ekler istiyorsanız Debug.Assert yerine Trace.Assert kullanabilirsiniz.

Bu elbette üretim yürütülebilir dosyaya ek yük getirir.

Ayrıca uygulamanız kullanıcı arabirimi modunda çalışıyorsa, varsayılan olarak Onaylama iletişim kutusu görüntülenir ve bu da kullanıcılarınız için biraz rahatsız edici olabilir.

DefaultTraceListener'ı kaldırarak bu davranışı geçersiz kılabilirsiniz: MSDN'deki Trace.Listeners belgelerine bakın.

Özetle,

  • Hata ayıklama yapılarında hataları yakalamak için Libug.Assert'i liberal olarak kullanın.

  • Kullanıcı arabirimi modunda Trace.Assert kullanırsanız, kullanıcıların rahatsız etmemesi için muhtemelen DefaultTraceListener'ı kaldırmak istersiniz.

  • Test ettiğiniz koşul uygulamanızın işleyemeyeceği bir şeyse, yürütmenin devam etmediğinden emin olmak için bir istisna atmanız daha iyi olur. Bir kullanıcının bir iddiayı göz ardı etmeyi seçebileceğini unutmayın.


1
OP özellikle üretim kodunu sorduğundan, Debug.Assert ve Trace.Assert arasındaki önemli ayrımı belirtmek için +1.
Jon Coombs

21

Ekler, kullanıcı hatasını değil programcı (sizin) hatasını yakalamak için kullanılır. Sadece bir kullanıcının savunucunun ateşleme şansı olmadığında kullanılmalıdır. Örneğin, bir API yazıyorsanız, bir API kullanıcısının arayabileceği herhangi bir yöntemde bağımsız değişkenin boş olmadığını kontrol etmek için varsayımlar kullanılmamalıdır. Ancak, API kodunuzun bir parçası olarak gösterilmeyen özel bir yöntemde, kodunuzun gerekmediğinde boş bir argüman iletmediğini iddia etmek için kullanılabilir.

Emin olmadığımda genellikle iddialar üzerinde istisnaları tercih ederim.


11

Kısacası

Asserts Muhafızlar ve Sözleşme kısıtlamalarına göre Tasarım kontrolü için kullanılır, yani:

  • AssertsHata Ayıklama ve Üretim Dışı derlemeler için olmalıdır. Sürüm sürümlerinde derleyiciler tarafından ekler genellikle yoksayılır.
  • Asserts Sisteminizin kontrolünde olan hataları / beklenmedik durumları kontrol edebilir
  • Asserts kullanıcı girişi veya iş kurallarının ilk satır doğrulaması için bir mekanizma DEĞİLDİR
  • Assertsgerektiği değil beklenebilir nadir olmakla birlikte, bu koşullar vardır mesela dışarı bellek, ağ hatası, veritabanı yetmezliği, vb (dışında kod kontrolü vardır) beklenmedik çevresel koşulların tespit etmek için kullanılabilir (ve uygulama kodu gibi sorunları tamir edemez donanım hatası veya kaynak tükenmesi). Genellikle istisnalar atılır - uygulamanız daha sonra düzeltici eylemde bulunabilir (örn. Bir veritabanını veya ağ işlemini yeniden deneyin, önbelleğe alınmış belleği boşaltmaya çalışın) veya istisna işlenemiyorsa nazikçe iptal edebilirsiniz.
  • Başarısız bir Onaylama sisteminiz için ölümcül olmalıdır - bir istisnadan farklı olarak, denemeye ve yakalamaya çalışmayın veya başarısız olmayın Asserts- kodunuz beklenmedik bir bölgede çalışıyor. Neyin yanlış gittiğini belirlemek için Yığın İzleri ve çökme dökümleri kullanılabilir.

İddiaların muazzam bir yararı var:

  • Daha yüksek düzey kodunda kullanıcı girişlerinin veya yukarı akış hatalarının eksik doğrulamasının bulunmasına yardımcı olmak için.
  • Kod tabanındaki ekler, kodda yapılan varsayımları açıkça okuyucuya iletir
  • Assert Debugderlemelerde çalışma zamanında kontrol edilecektir .
  • Kod kapsamlı bir şekilde test edildikten sonra, kodu Release olarak yeniden oluşturmak varsayımı doğrulama performans ek yükünü kaldıracaktır (ancak daha sonra bir Debug derlemesinin gerekirse kontrolleri her zaman geri döndürmesi avantajıyla).

... Daha fazla detay

Debug.AssertProgramın kontrolünde kod bloğunun geri kalanı tarafından durum hakkında varsayılan bir koşulu ifade eder. Bu, sağlanan parametrelerin durumunu, bir sınıf örneğinin üyelerinin durumunu veya bir yöntem çağrısından geri dönüşün sözleşmeli / tasarlanmış aralığında olmasını içerebilir. Tipik olarak, varsayımlar iş parçacığı / işlem / program için tasarlanmamış bir hata veya dikkate alınmamış bir durumun varlığını belirttiği için (Yığın İzi, Kilitlenme Dökümü, vb.) bir iddianın kendisinin hatadan daha fazla zarara neden olabileceği olası bir istisna dışında (örn. bir uçak denizaltıya gittiğinde Hava Trafik Kontrolörleri bir YSOD istemez, ancak bir hata ayıklama derlemesinin konuşlandırılıp dağıtılmayacağı tartışmalıdır. üretim ...)

Ne zaman kullanmalısınız Asserts? - Bir sınıfın bir işlevine veya durumuna girişlerin geçerli olduğu kabul edilen bir sistemde veya kitaplık API'sinde veya hizmetinde herhangi bir noktada (örneğin, bir sistemin sunum katmanındaki kullanıcı girişinde doğrulama yapıldığında) , işletme ve veri katmanı sınıfları genellikle girişte boş denetimler, aralık denetimleri, dize uzunluğu denetimleri vb. gerçekleştirilmiş olduğunu varsayar). - Yaygın Assertkontroller, geçersiz bir varsayımın null nesne dereference, sıfır bölen, sayısal veya tarih aritmetik taşması ve davranış için tasarlanmamış genel bant dışı / örn., Bir insanın yaşını modellemek için kullanıldıysa , Assertyaşın aslında 0 ile 125 arasında olması akıllıca olacaktır - -100 ve 10 ^ 10 değerleri için tasarlanmamıştır).

Net kod sözleşmeler
Net Yığın, içinde kod Sözleşme kullanılabilir ek olarak veya bir alternatif olarak kullanılarak Debug.Assert. Kod Sözleşmeleri, devlet denetimini daha fazla resmileştirebilir ve derleme zamanında varsayım ihlallerinin tespit edilmesine yardımcı olabilir (veya bir IDE'de arka plan kontrolü olarak çalıştırılırsa kısa bir süre sonra).

Sözleşme Tasarım (DBC) kontrolleri şunları içerir:

  • Contract.Requires - Sözleşmeli Ön Koşullar
  • Contract.Ensures - Sözleşmeli PostConditions
  • Invariant - Bir nesnenin kullanım ömrünün tüm noktalarındaki durumu ile ilgili bir varsayım ifade eder.
  • Contract.Assumes - Sözleşmesiz dekorlu yöntemlere çağrı yapıldığında statik denetleyiciyi pasifize eder.

Ne yazık ki, Kod Sözleşmeleri, MS'in geliştirmeyi bırakması nedeniyle tamamen ölüdür.
Mike Lowery

10

Çoğunlukla asla kitabımda. Her şeyin aklı başında olup olmadığını kontrol etmek istiyorsanız, o zaman büyük çoğunlukta değilse atın.

Sevmediğim şey, bir hata ayıklama derlemesini bir sürüm derlemesinden işlevsel olarak farklı kılmasıdır. Bir hata ayıklama iddiası başarısız olur, ancak işlevsellik sürümde çalışırsa, bunun nasıl bir anlamı var? İddiacı şirketten uzun zaman ayrıldığında ve kodun bu kısmını kimse bilmediğinde daha da iyi olur. O zaman gerçekten bir sorun olup olmadığını görmek için zaman keşfetmek bazı zaman öldürmek zorunda. Eğer bu bir problemse neden ilk etapta atmıyor?

Benim için bu Debug.Asserts kullanarak sorunu başka birine ertelediğinizi, sorunu kendiniz ele alacağınızı gösterir. Bir şey olması gerekiyorsa ve o zaman atmaz.

Tahminlerinizi optimize etmek istediğiniz muhtemelen performans açısından kritik senaryolar var ve bunlar orada kullanışlı, ancak henüz böyle bir senaryo ile karşılaşmıyorum.


4
Bunlarla ilgili sık sık endişe duyulan endişeleri, hata ayıklama oturumunu kesintiye uğratmaları ve yanlış pozitif olma şansını vurguladığınız halde, cevabınız bazı değerleri hak ediyor. Bununla birlikte, bazı incelikleri kaçırıyorsunuz ve yalnızca istisnaları atmanın ve debug.assert yapmanın aynı olduğunu düşünmeye dayanan "ekleri optimize et" yazıyorsunuz. Bu, yükseltilmiş bazı cevaplarda görebileceğiniz gibi, farklı amaçlara ve özelliklere hizmet eder. Dw
Casper Leon Nielsen

+1 "Sevmediğim şey, bir hata ayıklama derlemesini bir sürüm derlemesinden işlevsel olarak farklı kılmasıdır. Bir hata ayıklama iddiası başarısız olur, ancak işlevsellik sürümde çalışırsa, bu nasıl bir anlam ifade eder?" .NET'te, System.Diagnostics.Trace.Assert()bir Debug derlemesinin yanı sıra Release derlemesinde de çalışır.
DavidRR

7

Göre iDesign Standard , şunları yapmalısınız

Her varsayımı ileri sürün. Ortalama olarak, her beşinci satır bir iddiadır.

using System.Diagnostics;

object GetObject()
{...}

object someObject = GetObject();
Debug.Assert(someObject != null);

Bir feragatname olarak, bu IRL'nin uygulanmasını pratik bulmadım. Ama bu onların standardı.


Görünüşe göre Juval Lowy kendini alıntılamayı seviyor.
devlord

6

Yalnızca sürüm sürümleri için denetimin kaldırılmasını istediğiniz durumlarda iddiaları kullanın. Unutmayın, hata ayıklama modunda derlemezseniz iddialarınız tetiklenmeyecektir.

Null için çek örneğiniz göz önüne alındığında, bu yalnızca dahili bir API'daysa, bir onaylama kullanabilirim. Herkese açık bir API'daysa, kesinlikle açık çek ve atımı kullanırdım.


.NET'te, System.Diagnostics.Trace.Assert()bir sürüm (üretim) derlemesinde bir onaylama yürütmek için kullanılabilir .
DavidRR

Kod Çözümleme kuralı CA1062: Genel yöntemlerin bağımsız değişkenlerini doğrula, şu durumda bir bağımsız değişkenin denetlenmesini gerektirirnull : "Harici olarak görünür bir yöntem, bu bağımsız değişkenin boş olup olmadığını doğrulamaksızın başvuru bağımsız değişkenlerinden birini kaldırır ." Böyle bir durumda, yöntem veya özellik atmalıdır ArgumentNullException.
DavidRR

6

Tüm öneriler aşağıdakiler için optimize edilebilen kod olmalıdır:

Debug.Assert(true);

Çünkü daha önce var olduğunu düşündüğünüz bir şeyi kontrol ediyor. Örneğin:

public static void ConsumeEnumeration<T>(this IEnumerable<T> source)
{
  if(source != null)
    using(var en = source.GetEnumerator())
      RunThroughEnumerator(en);
}
public static T GetFirstAndConsume<T>(this IEnumerable<T> source)
{
  if(source == null)
    throw new ArgumentNullException("source");
  using(var en = source.GetEnumerator())
  {
    if(!en.MoveNext())
      throw new InvalidOperationException("Empty sequence");
    T ret = en.Current;
    RunThroughEnumerator(en);
    return ret;
  }
}
private static void RunThroughEnumerator<T>(IEnumerator<T> en)
{
  Debug.Assert(en != null);
  while(en.MoveNext());
}

Yukarıda, null parametrelere üç farklı yaklaşım vardır. Birincisi izin verilen olarak kabul eder (sadece hiçbir şey yapmaz). İkincisi, arama kodunun işlenmesi için bir istisna atar (veya bir hata mesajıyla sonuçlanır). Üçüncüsü bunun gerçekleşemeyeceğini varsayar ve böyle olduğunu iddia eder.

İlk durumda, sorun yok.

İkinci durumda, arama koduyla ilgili bir sorun var - GetFirstAndConsumenull ile çağrılmamalıydı , bu yüzden bir istisna geri geliyor.

Üçüncü durumda, bu kodla ilgili bir sorun var, çünkü daha en != nullönce çağrılmadan önce kontrol edilmiş olması gerekiyordu, böylece doğru değil bir hata. Ya da başka bir deyişle, teorik olarak optimize edilebilen kod olmalı Debug.Assert(true), sicne en != nullher zaman olmalı true!


1
Peki, üçüncü durumda, en == nullüretimde ne olur ? Belki söylüyorsunuz en == nulledebilirsiniz asla (program iyice ayıklanmış beri) üretimde oldu mu? Eğer öyleyse, Debug.Assert(en != null)en azından bir yoruma alternatif olarak hizmet eder. Tabii ki, gelecekteki değişiklikler yapılırsa, olası bir gerilemeyi tespit etmek için de değeri olmaya devam eder.
DavidRR

@DavidRR, ben gerçekten asla boş olamaz olduğunu iddia ediyorum, ve böylece kodda iddia, dolayısıyla adı. Elbette yanlış olabilirim, ya da bir değişiklikle yanlış yapılabilirdim ve bu iddia çağrısının değeri.
Jon Hanna

1
Çağrılar Debug.Assert()bir Yayın derlemesinde kaldırılır. Eğer Yani, olan yanlış, üçüncü durumda , siz (üretimde Bir yayın oluşturma kullanımını varsayarak) üretimde bunu bilmez. Ancak, hata ayıklama ve sürüm yapılarında birinci ve ikinci vakaların davranışı aynıdır.
DavidRR

@DavidRR, sadece bunun gerçekleşemeyeceğini düşündüğümde uygun kılar, yine bir gerçek iddiasıdır, durumun kontrolü değil. Tabii ki, eğer iddianıza sahipse, yakalayacağı bir hata varsa ve yine de testte bu davaya asla vurmak anlamsızdır.
Jon Hanna

4

Debug.Assert'in doğru seçim olabileceği dört vaka daha ekleyeceğimi düşündüm.

1) Burada bahsetmediğim bir şey, Eklemelerin otomatik test sırasında sağlayabileceği ek kavramsal kapsamdır . Basit bir örnek olarak:

Bazı üst düzey arayanlar, kodun kapsamını ek senaryoları ele alacak şekilde genişlettiklerine inanan bir yazar tarafından değiştirildiğinde, ideal olarak (!) Bu yeni koşulu kapsayacak şekilde birim testleri yazacaklardır. Bu durumda tam entegre kod düzgün çalışıyor gibi görünebilir.

Bununla birlikte, aslında ince bir kusur ortaya çıktı, ancak test sonuçlarında tespit edilmedi. Bu durumda callee belirleyici olmaz ve sadece beklenen sonucu verir. Ya da belki de fark edilmeyen bir yuvarlama hatası verdi. Veya başka bir yerde eşit olarak dengelenen bir hataya neden oldu. Veya yalnızca istenen erişim değil, verilmemesi gereken ek ayrıcalıklar da verildi. Vb.

Bu noktada, callee'de yer alan Debug.Assert () ifadeleri, birim testleri tarafından çalıştırılan yeni vaka (veya kenar durumu) ile birleştiğinde, test sırasında orijinal yazarın varsayımlarının geçersiz kılındığına ve kodun ek inceleme yapılmadan yayınlanabilir. Birim testleri ile zenginleştirmeler mükemmel ortaklardır.

2) Ek olarak, bazı testlerin yazılması kolaydır, ancak ilk varsayımlar dikkate alındığında yüksek maliyetlidir ve gereksizdir . Örneğin:

Bir nesneye yalnızca belirli bir güvenli giriş noktasından erişilebiliyorsa, arayanın izinleri olduğundan emin olmak için her nesne yönteminden bir ağ hakları veritabanına ek bir sorgu yapılmalı mıdır? Kesinlikle hayır. Belki de ideal çözüm, önbellekleme veya özelliklerin başka bir şekilde genişletilmesini içerir, ancak tasarım bunu gerektirmez. Nesne güvenli olmayan bir giriş noktasına eklendiğinde hemen bir Debug.Assert () gösterilir.

3) Daha sonra, bazı durumlarda ürününüz, serbest bırakma modunda dağıtıldığında işlemlerinin tümü veya bir kısmı için yararlı bir tanı etkileşimi olmayabilir . Örneğin:

Diyelim ki gömülü bir gerçek zamanlı cihaz. İstisnalar atmak ve hatalı biçimlendirilmiş bir paketle karşılaştığında yeniden başlatmak karşı üretkendir. Bunun yerine, cihaz, çıkışında gürültü yaratma noktasına kadar en iyi çabadan yararlanabilir. Ayrıca, bir insan arabirimi, kayıt cihazı olmayabilir veya serbest bırakma modunda dağıtıldığında insan tarafından fiziksel olarak erişilebilir olmayabilir ve hataların farkındalığı en iyi şekilde aynı çıktı değerlendirilerek sağlanır. Bu durumda, liberal iddialar ve kapsamlı tahliye öncesi testler istisnalardan daha değerlidir.

4) Son olarak, bazı testler sadece callee'nin son derece güvenilir olduğu için gereksizdir . Çoğu durumda, yeniden kullanılabilir kod ne kadar çoksa, güvenilir hale getirmek için o kadar fazla çaba harcanır. Bu nedenle, arayanlardan beklenmeyen parametreler için Exception'da yaygındır, ancak callees'ten beklenmeyen sonuçlar için Assert kullanılır. Örneğin:

Bir çekirdek String.Findişlem -1arama ölçütleri bulunmadığında bir geri döneceğini bildirirse , üç yerine bir işlemi güvenli bir şekilde gerçekleştirebilirsiniz. Ancak, gerçekte geri döndüyse -2, makul bir hareket tarzınız olmayabilir. Daha basit hesaplamayı, bir -1değeri ayrı ayrı test eden bir hesapla değiştirmek yararsızdır ve çoğu sürüm ortamında kodlarınızı çekirdek kütüphanelerin beklendiği gibi çalıştığından emin olmak için test etmek için mantıksızdır. Bu durumda Eklemler idealdir.


4

Pragmatik Programcıdan Alıntı : Journeyman'dan Master'a

Bildirileri Açık Bırak

Derleyiciler ve dil ortamları yazan insanlar tarafından ileri sürülen iddialarla ilgili yaygın bir yanlış anlama vardır. Böyle bir şey gider:

İddialar koda ek yük getirir. Asla olmaması gereken şeyleri kontrol ettikleri için, sadece koddaki bir hata tarafından tetiklenirler. Kod test edildikten ve gönderildikten sonra, artık gerekli değildir ve kodun daha hızlı çalışmasını sağlamak için kapatılmalıdır. İddialar bir hata ayıklama tesisidir.

Burada iki tane yanlış yanlış varsayım var. İlk olarak, testin tüm hataları bulduğunu varsayarlar. Gerçekte, herhangi bir karmaşık program için kodunuzun geçireceği permütasyonların küçük bir yüzdesini bile test etmeniz olası değildir (bkz. Acımasız Testler).

İkincisi, iyimserler programınızın tehlikeli bir dünyada çalıştığını unutuyorlar. Testler sırasında sıçanlar muhtemelen bir iletişim kablosundan kemilmez, oyun oynayan biri hafızayı tüketmez ve günlük dosyaları sabit sürücüyü doldurmaz. Bunlar, programınız bir üretim ortamında çalıştığında olabilir. İlk savunma hattınız olası herhangi bir hatayı kontrol ediyor ve ikinciniz kaçırdığınızları tespit etmek için iddialar kullanıyor.

Bir programı üretime teslim ettiğinizde iddiaları kapatmak, bir zamanlar pratikte geçtiğiniz için yüksek bir teli ağ olmadan geçmek gibidir . Dramatik bir değer var, ancak hayat sigortası yaptırmak zor.

Performans sorunlarınız olsa bile, yalnızca size gerçekten çarpan iddiaları kapatın .


2

Her zaman ikinci yaklaşımı kullanmalısınız (istisnalar atma).

Ayrıca üretimde iseniz (ve bir sürüm oluşturma işlemine sahipseniz), geçersiz değerlerle çalışmaktan ve belki de müşterinizin verilerini (bin dolar).


1
Hayır, buradaki diğer cevaplarla aynı: farkı gerçekten anlamıyorsunuz, bu yüzden tekliflerden birini seçip süreçte yanlış bir ikilik oluşturuyorsunuz. Dw
Casper Leon Nielsen

3
Bu IMO listesindeki tek doğru cevaptır. Casper'ı bu kadar kolay reddetme. Hata Ayıklama Assert bir anti-kalıptır. Hata ayıklama zamanında değişmezse, çalışma zamanında değişmez. Uygulamanızın kırık bir değişmezle devam etmesine izin vermek, sizi belirleyici olmayan bir durumda ve kilitlenmekten daha kötü problemler bırakır. IMO, her iki derlemede de kırık sözleşmelerle hızlı bir şekilde başarısız olan ve daha sonra en üst düzeyde sağlam hata işleme uygulayan aynı kodu kullanmak daha iyidir. Örneğin bileşenleri ayırın ve yeniden başlatma yeteneğini uygulayın (tarayıcıda kilitlenen bir sekme tüm tarayıcıyı kilitlemiyor gibi).
justin.m.chase

1
Trace.Assert'i tartışmanıza buraya dahil etmek yararlı olabilir, çünkü aynı argüman tarafından reddedilemez.
Jon Coombs

0

Programlarınızdaki mantıksal hataları test etmek için Debug.Assert'i kullanmalısınız. Complier yalnızca sözdizimi hatalarını size bildirebilir. Bu nedenle mantıksal hataları test etmek için Assert deyimlerini kesinlikle kullanmalısınız. Diyelim ki, yalnızca mavi olan BMW'lerin% 15 indirim alması gerektiğini otomobil satan bir program test etmek gibi. Complier, programınızın bunu yaparken mantıksal olarak doğru olup olmadığı hakkında hiçbir şey söyleyemez, ancak bir assert deyimi olabilir.


2
üzgünüm ama istisnalar aynı şeyleri yapıyor, bu yüzden bu cevap gerçek soruyu ele almıyor
Roman Starkov

0

Burada cevapları okudum ve önemli bir ayrım eklemem gerektiğini düşündüm. Eklerin kullanıldığı çok farklı iki yol vardır. Bunlardan biri, programınızın devam edebildiği durumlar için, "Bu gerçekten olmamalı, bu yüzden bana ne yapacağımı karar verebilmem için bana izin verirse", bir tür koşullu kesme noktası gibi geçici bir geliştirici kısayolu olarak. Diğeri, kodunuza geçerli program durumları hakkında varsayımlar koymanın bir yoludur.

İlk durumda, iddiaların nihai kodda olması bile gerekmez. Debug.AssertGeliştirme sırasında kullanmalısınız ve artık gerekmediğinde / gerektiğinde bunları kaldırabilirsiniz. Onları bırakmak istiyorsanız veya bunları kaldırmayı unutursanız, Sürüm derlemelerinde herhangi bir sonucu olmayacağı için sorun yok.

Ancak ikinci durumda, iddialar kodun bir parçasıdır. Varsayımlarınızın doğru olduğunu iddia ediyorlar ve bunları belgeliyorlar. Bu durumda, onları gerçekten kodda bırakmak istersiniz. Program geçersiz bir durumdaysa, devam etmesine izin verilmemelidir. Performans vuruşunu karşılayamazsanız, C # kullanamazsınız. Bir yandan, bir hata ayıklayıcı gerçekleşirse eklenebilir. Öte yandan, yığın izinin kullanıcılarınızda açılmasını istemezsiniz ve belki de daha önemlisi, onları görmezden gelmelerini istemezsiniz. Ayrıca, bir hizmette ise her zaman göz ardı edilecektir. Bu nedenle üretimde doğru davranış, bir İstisna atmak ve programınızın normal istisna işlemeyi kullanmak olacaktır, bu da kullanıcıya güzel bir mesaj gösterebilir ve ayrıntıları günlüğe kaydedebilir.

Trace.Assertbunu başarmak için mükemmel bir yol var. Üretimde kaldırılmaz ve app.config kullanılarak farklı dinleyicilerle yapılandırılabilir. Bu nedenle geliştirme için varsayılan işleyici iyidir ve üretim için aşağıdaki gibi basit bir TraceListener oluşturabilirsiniz, bu da bir istisna atar ve üretim yapılandırma dosyasında etkinleştirir.

using System.Diagnostics;

public class ExceptionTraceListener : DefaultTraceListener
{
    [DebuggerStepThrough]
    public override void Fail(string message, string detailMessage)
    {
        throw new AssertException(message);
    }
}

public class AssertException : Exception
{
    public AssertException(string message) : base(message) { }
}

Ve üretim yapılandırma dosyasında:

<system.diagnostics>
  <trace>
    <listeners>
      <remove name="Default"/>
      <add name="ExceptionListener" type="Namespace.ExceptionTraceListener,AssemblyName"/>
    </listeners>
  </trace>
 </system.diagnostics>

-1

Nasıl C # ve .NET olduğunu bilmiyorum, ama C assert () sadece -DDEBUG ile derlenirse çalışır - enduser olmadan derlenmiş bir assert () görmezsiniz. Sadece geliştirici içindir. Gerçekten sık kullanıyorum, bazen hataları izlemek daha kolay.


-1

Onları üretim kodunda kullanmazdım. İstisnalar atın, yakalayın ve günlüğe kaydedin.

Konsolda bir iddia ortaya çıkabileceği ve istekleri dondurduğu için asp.net'te de dikkatli olmanız gerekir.

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.