c# #if DEBUG बनाम सशर्त("DEBUG")




debugging preprocessor (6)

खैर, यह ध्यान देने योग्य है कि उनका मतलब बिल्कुल वही नहीं है।

यदि DEBUG प्रतीक परिभाषित नहीं किया गया है, तो पहले मामले में SetPrivateValue स्वयं को नहीं बुलाया जाएगा ... जबकि दूसरे मामले में यह अस्तित्व में रहेगा, लेकिन किसी भी कॉलर जिन्हें DEBUG प्रतीक के बिना संकलित किया गया है, उन कॉलों को छोड़ दिया जाएगा।

यदि कोड और उसके सभी कॉलर एक ही असेंबली में हैं तो यह अंतर कम महत्वपूर्ण है - लेकिन इसका मतलब है कि पहले मामले में आपको कॉलिंग कोड के आसपास #if DEBUG भी होना चाहिए।

व्यक्तिगत रूप से मैं दूसरे दृष्टिकोण की सिफारिश करता हूं - लेकिन आपको उनके सिर में स्पष्ट अंतर रखने की आवश्यकता है।

उपयोग करने के लिए बेहतर कौन सा है, और क्यों, एक बड़ी परियोजना पर:

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

या

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

पहले उदाहरण के साथ, DEBUG को परिभाषित नहीं किया गया है, तो SetPrivateValue निर्माण में मौजूद नहीं होगा, दूसरे उदाहरण के साथ, SetPrivateValue को कॉल में DEBUG परिभाषित नहीं किया गया है, तो निर्माण में मौजूद नहीं होगा।

पहले उदाहरण के साथ, आपको #if DEBUG साथ SetPrivateValue किसी भी कॉल को SetPrivateValue

दूसरे उदाहरण के साथ, SetPrivateValue कॉल छोड़े जाएंगे, लेकिन ध्यान रखें कि SetPrivateValue स्वयं भी संकलित हो जाएगा। यदि आप लाइब्रेरी बना रहे हैं तो यह उपयोगी है, इसलिए आपकी लाइब्रेरी का संदर्भ देने वाला एक एप्लिकेशन अभी भी आपके फ़ंक्शन का उपयोग कर सकता है (यदि स्थिति पूरी हो जाती है)।

यदि आप कॉल को छोड़ना चाहते हैं और कैली की जगह को सहेजना चाहते हैं, तो आप दो तकनीकों के संयोजन का उपयोग कर सकते हैं:

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

आइए मान लीजिए कि आपके कोड में एक #else कथन भी था जो जॉन स्कीट के अंक को संबोधित करते हुए एक नल स्टब फ़ंक्शन को परिभाषित करता था। दोनों के बीच एक दूसरा महत्वपूर्ण अंतर है।

मान लीजिए कि #if DEBUG या Conditional फ़ंक्शन एक डीएलएल में मौजूद है जिसे आपके मुख्य प्रोजेक्ट निष्पादन योग्य द्वारा संदर्भित किया गया है। #if का उपयोग करके, सशर्त का मूल्यांकन पुस्तकालय की संकलन सेटिंग्स के संबंध में किया जाएगा। Conditional विशेषता का उपयोग करके, Conditional का मूल्यांकन आवेदक की संकलन सेटिंग्स के संबंध में किया जाएगा।


मुझे यकीन है कि बहुत सारे मेरे साथ असहमत होंगे, लेकिन एक बिल्डिंग लड़के के रूप में समय बिताने के लिए लगातार समय बिताते हैं "लेकिन यह मेरी मशीन पर काम करता है!", मैं दृष्टिकोण लेता हूं कि आपको कभी भी कभी भी इसका उपयोग नहीं करना चाहिए। यदि आपको वास्तव में परीक्षण और डिबगिंग के लिए कुछ चाहिए, तो वास्तविक उत्पादन कोड से उस टेस्टेबिलिटी को अलग करने का एक तरीका जानें।

यूनिट परीक्षणों में मजाक करने वाले परिदृश्यों को सार बनाएं, उन परिदृश्यों के लिए चीजों के संस्करणों को बंद करें जिन्हें आप परीक्षण करना चाहते हैं, लेकिन उत्पादन रिलीज के लिए परीक्षण और लिखने वाली बाइनरी के लिए कोड में डीबग करने के लिए परीक्षण न करें। ये डीबग परीक्षण केवल देवों से संभावित बग छिपाते हैं ताकि वे प्रक्रिया में बाद में नहीं पाए जाते।


मेरे पास कस्टम [TraceExtension] का उपयोग करके नेटवर्क ट्रैफ़िक लॉग करने के लिए एक SOAP वेब सेवा एक्सटेंशन है। मैं केवल डीबग बिल्ड के लिए इसका उपयोग करता हूं और रिलीज बिल्ड से निकलता हूं। [TraceExtension] विशेषता को लपेटने के लिए #if DEBUG का उपयोग करें जिससे इसे रिलीज बिल्ड से हटा दिया जा सके।

#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(...)

यह वास्तव में इस बात पर निर्भर करता है कि आप किसके लिए जा रहे हैं:

  • #if DEBUG : यहां का कोड रिलीज पर आईएल तक नहीं पहुंच पाएगा।
  • [Conditional("DEBUG")] : यह कोड आईएल तक पहुंच जाएगा, हालांकि कॉलर संकलित होने पर DEBUG सेट होने तक विधि को कॉल छोड़ दिया जाएगा।

व्यक्तिगत रूप से मैं स्थिति के आधार पर दोनों का उपयोग करता हूं:

सशर्त ("DEBUG") उदाहरण: मैं इसका उपयोग करता हूं ताकि मुझे वापस जाने और रिलीज के दौरान बाद में अपना कोड संपादित करने की आवश्यकता न हो, लेकिन डीबगिंग के दौरान मैं यह सुनिश्चित करना चाहता हूं कि मैंने कोई टाइपो नहीं बनाया है। यह फ़ंक्शन जांचता है कि मैं अपने INotifyPropertyChanged सामान में इसका उपयोग करने का प्रयास करते समय सही ढंग से एक संपत्ति का नाम टाइप करता हूं।

[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));
}

आप वास्तव में #if DEBUG का उपयोग करके कोई फ़ंक्शन नहीं बनाना चाहते हैं जब तक कि आप उस कॉल पर प्रत्येक कॉल को उसी #if DEBUG साथ लपेटने के इच्छुक न हों:

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

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

बनाम:

[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 उदाहरण: डब्ल्यूसीएफ संचार के लिए अलग-अलग बाइंडिंग सेट करने का प्रयास करते समय मैं इसका उपयोग करता हूं।

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

पहले उदाहरण में, कोड सभी मौजूद है, लेकिन जब तक DEBUG चालू नहीं होता तब तक केवल अनदेखा किया जाता है। दूसरे उदाहरण में, यदि DEBUG सेट किया गया है या नहीं, तो आधार ENDPOINT "लोकलहोस्ट" या "बेसिकहेट बाइंडिंग" पर सेट है।

अद्यतन: मैं एक महत्वपूर्ण और मुश्किल बिंदु को स्पष्ट करने के लिए यह उत्तर अपडेट कर रहा हूं। यदि आप ConditionalAttribute का उपयोग करना चुनते हैं, तो ध्यान रखें कि संकलन के दौरान कॉल छोड़ी जाती है, और रनटाइम नहीं होती है । अर्थात्:

MyLibrary.dll

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

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

जब लाइब्रेरी को रिहाई मोड (यानी कोई डेब्यूजी प्रतीक) के खिलाफ संकलित नहीं किया जाता है, तो हमेशा A() भीतर से B() को कॉल किया जाएगा, भले ही A() को कॉल किया गया हो क्योंकि कॉलिंग असेंबली में डीबीयूजी परिभाषित किया गया है ।





debug-symbols