#if DEBUG ve Koşullu (“DEBUG”)


432

Hangi büyük bir projede kullanmak daha iyidir ve neden:

#if DEBUG
    public void SetPrivateValue(int value)
    { ... }
#endif

veya

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }

18
Bu soru hakkında bazı düşünceler için blogs.msdn.com/b/ericlippert/archive/2009/09/10/… adresine bakın .
Eric Lippert

2
bunu da kullanabilirsiniz: if (Debugger.IsAttached) {...}
sofsntp

Unity geliştiricileri için not: DEBUG, editör veya geliştirme sürümlerinde anlamına gelir. forum.unity.com/threads/…
KevinVictor

Yanıtlar:


578

Gerçekten ne istediğinize bağlı:

  • #if DEBUG: Buradaki kod serbest bırakıldığında IL'ye bile ulaşmayacak.
  • [Conditional("DEBUG")]: Bu kod IL'ye ulaşacaktır, ancak arayan derlendiğinde DEBUG ayarlanmadığı sürece yönteme çağrılar atlanacaktır.

Şahsen ben duruma bağlı olarak her ikisini de kullanıyorum:

Koşullu ("DEBUG") Örnek: Geriye dönüp daha sonra yayın sırasında kodumu düzenlemek zorunda kalmamam için bunu kullanıyorum, ancak hata ayıklama sırasında herhangi bir yazım hatası yapmadığımdan emin olmak istiyorum. Bu işlev, INotifyPropertyChanged öğelerimde kullanmaya çalışırken bir özellik adını doğru yazdığımı denetler.

[Conditional("DEBUG")]
[DebuggerStepThrough]
protected void VerifyPropertyName(String propertyName)
{
    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}",
            GetType(), propertyName));
}

Bu işleve yapılan #if DEBUGher çağrıyı aynı şekilde sarmak istemiyorsanız, gerçekten kullanarak bir işlev oluşturmak istemezsiniz #if DEBUG:

#if DEBUG
    public void DoSomething() { }
#endif

    public void Foo()
    {
#if DEBUG
        DoSomething(); //This works, but looks FUGLY
#endif
    }

karşı:

[Conditional("DEBUG")]
public void DoSomething() { }

public void Foo()
{
    DoSomething(); //Code compiles and is cleaner, DoSomething always
                   //exists, however this is only called during DEBUG.
}

#if DEBUG örneği: WCF iletişimi için farklı bağlantılar kurmaya çalışırken bunu kullanıyorum.

#if DEBUG
        public const String ENDPOINT = "Localhost";
#else
        public const String ENDPOINT = "BasicHttpBinding";
#endif

İlk örnekte, kodun tamamı vardır, ancak DEBUG açık olmadığı sürece yok sayılır. İkinci örnekte, DEBUG öğesinin ayarlanıp ayarlanmadığına bağlı olarak const ENDPOINT öğesi "Localhost" veya "BasicHttpBinding" olarak ayarlanır.


Güncelleme: Önemli ve zor bir noktayı açıklığa kavuşturmak için bu cevabı güncelliyoruz. Seçeneğini kullanmayı seçerseniz ConditionalAttribute, aramaların derleme sırasında değil çalışma sürelerinin dikkate alınmadığını unutmayın . Yani:

MyLibrary.dll

[Conditional("DEBUG")]
public void A()
{
    Console.WriteLine("A");
    B();
}

[Conditional("DEBUG")]
public void B()
{
    Console.WriteLine("B");
}

Kütüphane sürüm modunda (yani hiçbir DEBUG sembolü) karşı derlenmiş zaman, sonsuza çağrısına sahip olacak B()içinden A(), atlanmış olsa bile yapılan bir çağrı A()DEBUG montaj arayarak tanımlanmış olması nedeniyle dahildir.


13
# If Debug for Debugething, #if DEBUG ile çevrelenen tüm çağrı ifadelerine sahip olmak zorunda değildir. 1: DoSomething'in içini DEBUG yapın ya da boş bir DoSomething tanımıyla #else yapabilirsiniz. Yine de yorumunuz farkı anlamama yardımcı oldu, ancak # DEBUG'ın gösterdiğiniz kadar çirkin olması gerekmez.
Apeiron

3
Eğer içeriği # DEBUG yaparsanız, kodunuz hata ayıklamayan bir derlemede çalıştığında JIT hala işleve çağrı içerebilir. Koşullu özniteliği kullanmak, JIT DEBUG olmayan bir yapıdayken çağrı sitesi bile çıkmamayı bilir anlamına gelir.
Jeff Yates

2
@JeffYates: Yazdıklarınızın açıkladığımdan ne kadar farklı olduğunu görmüyorum.
Benim

1
@Apeiron, yalnızca #if hata ayıklamasında işlev içeriğine sahipseniz, işlev çağrısı hala çağrı yığınına eklenir, ancak bu genellikle çok önemli olmasa da, #if işlevine bildirim ve işlev çağrısı eklenmesi derleyicinin işlev yoksa, benim yöntemim #if kullanmanın daha "doğru" yoludur. her iki yöntem de normal kullanımda birbirinden ayırt edilemeyen sonuçlar üretir
MikeT

5
merak
edenler

64

Aynı şeyi hiç anlamadıklarını belirtmek gerekir.

Eğer DEBUG sembolü tanımlanmamışsa, ilk durumda SetPrivateValuekendisi çağrılmaz ... ikinci durumda mevcut olacaktır, ancak DEBUG sembolü olmadan derlenen arayanlar bu çağrıları atlayacaktır.

Kod ve tüm arayanları aynı montajdaysa, bu fark daha az önemlidir - ancak ilk durumda arama kodunun etrafında da olması gerektiği anlamına gelir .#if DEBUG

Şahsen ikinci yaklaşımı öneriyorum - ama aralarındaki farkı kafanızda açık tutmanız gerekiyor.


5
Arama kodu için + 1'in de #if ifadeleri olması gerekir. Bu, # if ifadelerinin çoğalması olacağı anlamına gelir ...
Lucas B

İkinci seçenek (Koşullu öznitelik) bazı durumlarda daha güzel ve daha temiz olsa da, bir yöntem çağrısının derleme sırasında derlemeden çıkarılacağı gerçeğini bildirmek gerekebilir (örneğin bir adlandırma kuralıyla).
lysergic-acid

45

Eminim benimle aynı fikirde değil, ama sürekli "Ama benim makinemde çalışıyor!" Diye işitme yapan bir adam olarak zaman geçirdim, ben de hemen hemen hiç kullanmamalısınız bakış açısını alıyorum. Test ve hata ayıklama için gerçekten bir şeye ihtiyacınız varsa, test edilebilirliği gerçek üretim kodundan ayırmanın bir yolunu bulun.

Birim testlerinde alaycı senaryoları soyutlayın, test etmek istediğiniz bir kerelik senaryolar için bir kereye mahsus sürümler yapın, ancak üretim sürümü için test edip yazdığınız ikili kodlar için hata ayıklama testleri koymayın. Bu hata ayıklama testleri, olası hataları geliştiricilerden gizler, böylece işlemin sonrasına kadar bulunamazlar.


4
Sana tamamen katılıyorum Jimmy. Testleriniz için DI kullanıyorsanız ve alay ediyorsanız #if debug, kodunuzda neden benzer bir yapıya ihtiyacınız var ?
Richard Ev

@RichardEv Bunu işlemek için daha iyi bir yol olabilir, ama şu anda kendimi bir sorgu dizesi aracılığıyla farklı kullanıcıların bir kısmını oynamak için izin için kullanıyorum. Üretimde bunu istemiyorum ama hata ayıklama için bunu istiyorum, böylece birden fazla kullanıcı oluşturmak ve akış boyunca yürümek için her iki hesaba giriş yapmadan atlanan iş akışını kontrol edebilirim. Gerçi bu ilk defa kullanmak zorunda kaldım.
Tony

4
Sadece test için değil, genellikle hata ayıklama yapılarında kendimize varsayılan bir alıcı e-postası ayarlamak gibi işlemler yaparız, #if DEBUGböylece sürecin bir parçası olarak e-posta iletmesi gereken bir sistemi test ederken başkalarını yanlışlıkla spam etmeyiz. Bazen bunlar iş için doğru araçlardır :)
Gone Coding

6
Genel olarak sizinle aynı fikirde olurdum ancak performansın çok önemli olduğu bir durumdaysanız, kodu harici günlük kaydı ve kullanıcı çıktısı ile karıştırmak istemezsiniz, ancak% 100 hiç değiştirmek için kullanılmaması gerektiğini kabul ediyorum temel davranış
MikeT

5
-1 Bunlardan birini kullanmanın yanlış bir yanı yok. Ünite testlerini ve DI'yi talep etmek, bir ürünün hata ayıklama özellikli yapısının naif olduğunu bir şekilde değiştirir.
Ted Bigham

15

Bu da yararlı olabilir:

if (Debugger.IsAttached)
{
...
}

1
Şahsen, bunun diğer 2 alternatife kıyasla nasıl yararlı olabileceğini görmüyorum. Bu, tüm bloğun derlendiğini ve Debugger.IsAttachedyayın sürümlerinde bile çalışma zamanında çağrılması gerektiğini garanti eder .
Jai

9

İlk örnek ile, SetPrivateValueeğer yapı içinde mevcut olmayacaktır DEBUGtanımlanmış olan ikinci bir örnek ile, aramalar için SetPrivateValue, eğer yapı içinde mevcut olmayacaktır DEBUGtanımlanmamıştır.

İlk örnekte, tüm çağrıları da SetPrivateValueile sarmanız gerekir #if DEBUG.

İkinci örnekte, çağrılar SetPrivateValueatlanacak, ancak SetPrivateValueyine de derleneceğini unutmayın. Bu, bir kitaplık oluşturuyorsanız yararlıdır, bu nedenle kitaplığınıza başvuran bir uygulama yine de işlevinizi kullanabilir (koşul karşılanırsa).

Çağrıları atlamak ve arayanın alanından tasarruf etmek istiyorsanız, iki tekniğin bir kombinasyonunu kullanabilirsiniz:

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
    #if DEBUG
    // method body here
    #endif
}

@P Baba: Sarma #if DEBUGetrafında Conditional("DEBUG")hala (derleme hataları) yok işlevine çağrıları yaşıyorsanız bu nedenle, sadece alltogether IL fonksiyonunu kaldırır, bu işleve çağrı kaldırmaz.
Benim

1
Kodun sürümde var olmasını istemiyorsanız, yöntem gövdesini "#if DEBUG" içine, muhtemelen bir "#else" saplamasıyla (bir atma veya kukla döndürme değeriyle) sarmalı ve önermek için niteliği kullanmalıdır. Arayanlar aramayı rahatsız etmiyor mu? Bu her iki dünyanın en iyisi gibi görünüyor.
supercat

@ myermian, @supercat: Evet, ikiniz de haklısınız. Benim hatam. Supercat'in önerisine göre düzenleyeceğim.
P Daddy

5

Kodunuzun ayrıca #else, Jon Skeet'in noktalarından birine hitap eden bir boş saplama işlevi tanımlayan bir ifade olduğunu varsayalım . İkisi arasında ikinci önemli bir ayrım var.

#if DEBUGVeya Conditionalişlevinin, ana proje yürütülebiliriniz tarafından başvurulan bir DLL dosyasında var olduğunu varsayalım . Kullanılarak, #ifkoşulun değerlendirilmesi kütüphanenin derleme ayarlarına göre yapılacaktır. Bu Conditionalözniteliği kullanarak, koşullu değerlendirmesi davetlinin derleme ayarlarına göre yapılacaktır.


2

Bir özel kullanarak ağ trafiğini günlüğe kaydetmek için bir SOAP WebService uzantısı var [TraceExtension]. Ben sadece Debug derlemeleri için kullanın ve Release derlemeler atlayın . Özniteliği #if DEBUGsarmak için kullanın ve [TraceExtension]böylece Release derlemelerinden kaldırın.

#if DEBUG
[TraceExtension]
#endif
[System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )]
[ more attributes ...]
public DatabaseResponse[] GetDatabaseResponse( ...) 
{
    object[] results = this.Invoke("GetDatabaseResponse",new object[] {
          ... parmeters}};
}

#if DEBUG
[TraceExtension]
#endif
public System.IAsyncResult BeginGetDatabaseResponse(...)

#if DEBUG
[TraceExtension]
#endif
public DatabaseResponse[] EndGetDatabaseResponse(...)

0

Genellikle Program.cs dosyasında, hata ayıklama yapmadan hata ayıklama kodunu çalıştırmaya karar vermek istediğiniz programa ihtiyacınız vardır. Bu yüzden salt okunur bir alan IsDebugMode oluşturdum ve değerini aşağıda gösterildiği gibi statik yapıcıda ayarladım.

static class Program
{

    #region Private variable
    static readonly bool IsDebugMode = false;
    #endregion Private variable

    #region Constrcutors
    static Program()
    {
 #if DEBUG
        IsDebugMode = true;
 #endif
    }
    #endregion

    #region Main

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(string[] args)
    {

        if (IsDebugMode)
        {
            MyService myService = new MyService(args);
            myService.OnDebug();             
        }
        else
        {
            ServiceBase[] services = new ServiceBase[] { new MyService (args) };
            services.Run(args);
        }
    }

    #endregion Main        
}
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.