#if डेबग बनाम सशर्त ("डेबग")


432

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

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

या

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

18
इस प्रश्न पर कुछ विचारों के लिए ब्लॉगs.msdn.com/b/ericlippert/archive/2009/09/10/… देखें ।
एरिक लिपर्ट

2
आप इसे भी उपयोग कर सकते हैं: if (Debugger.IsAttached) {...}
sofsntp

एकता डेवलपर्स के लिए ध्यान दें: DEBUG का मतलब संपादक में या विकास में होता है। forum.unity.com/threads/…
केविनविक्टर

जवाबों:


578

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

  • #if DEBUG: यहाँ कोड भी रिलीज़ पर IL तक नहीं पहुंचेगा।
  • [Conditional("DEBUG")]: यह कोड IL तक पहुंच जाएगा, हालाँकि कॉल करने के लिए संकलित होने पर 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 उदाहरण: WCF संचार के लिए अलग-अलग बाइंडिंग सेट करने का प्रयास करते समय मैं इसका उपयोग करता हूं।

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

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


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

MyLibrary.dll

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

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

जब लाइब्रेरी को रिलीज़ मोड (अर्थात कोई DEBUG प्रतीक) के विरुद्ध संकलित किया जाता है, तो इसमें हमेशा के लिए छोड़ दिया गया के B()भीतर से कॉल होगा A(), भले ही कोई कॉल A()शामिल हो क्योंकि DEBUG को कॉलिंग असेंबली में परिभाषित किया गया है।


13
DoSomething के लिए #if डिबग को #if DEBUG से घिरे सभी कॉलिंग स्टेटमेंट की आवश्यकता नहीं है। आप या तो 1: DoSomething के अंदर #if DEBUG कर सकते हैं, या, DoSomething की रिक्त परिभाषा के साथ एक #else करें। फिर भी आपकी टिप्पणी से मुझे अपने अंतर को समझने में मदद मिली, लेकिन #if DEBUG को आपके प्रदर्शन के अनुसार उतना बदसूरत नहीं होना चाहिए।
एपिरॉन

3
यदि आप सामग्री को केवल #if से हटाते हैं, तो JIT अभी भी फ़ंक्शन में एक कॉल शामिल कर सकता है जब आपका कोड एक गैर-डिबग बिल्ड में चलता है। सशर्त विशेषता का उपयोग करने का अर्थ है कि जेआईटी को पता है कि जब कॉल गैर-डीबग बिल्ड में होता है तब भी आउटपुट नहीं करता है।
जेफ येट्स

2
@JeYYYates: मैं यह नहीं देखता कि आप जो लिख रहे हैं वह मेरे द्वारा बताए गए तरीकों से अलग है।
मेरा

1
@ एपिरॉन यदि आपके पास केवल #if डिबग में फ़ंक्शन सामग्री है, तो फ़ंक्शन कॉल अभी भी कॉल स्टैक में जोड़ा जाता है, जबकि यह आमतौर पर बहुत महत्वपूर्ण नहीं होता है, घोषणा को जोड़ने और #if को फ़ंक्शन कॉल का अर्थ है कि कंपाइलर व्यवहार करता है यदि फ़ंक्शन मौजूद नहीं है, तो मेरी विधि #if का उपयोग करने का अधिक "सही" तरीका है। हालांकि दोनों विधियाँ ऐसे परिणाम उत्पन्न करती हैं जो सामान्य उपयोग में एक दूसरे से
अविभाज्य

5
अगर किसी की सोच है, IL = मध्यवर्ती भाषा - en.wikipedia.org/wiki/Common_Intermediate_Language
jbyrd

64

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

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

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

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


5
कॉलिंग कोड के लिए +1 में #if स्टेटमेंट भी होना चाहिए। जिसका अर्थ है # बयानों का प्रसार होगा ...
लुकास बी

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

45

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

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


4
मैं आपसे पूरी तरह से सहमत हूं जिमी। यदि आप अपने परीक्षणों के लिए DI और मॉकिंग का उपयोग कर रहे हैं, तो आपको #if debugअपने कोड में किसी भी समान निर्माण की आवश्यकता क्यों होगी ?
रिचर्ड ईव

@RichardEv इसे संभालने का एक बेहतर तरीका हो सकता है, लेकिन मैं वर्तमान में इसका उपयोग खुद को क्वेरी स्ट्रिंग के माध्यम से विभिन्न उपयोगकर्ताओं के हिस्से को चलाने की अनुमति देने के लिए कर रहा हूं। मैं उत्पादन में यह नहीं चाहता, लेकिन मैं इसे डिबगिंग के लिए चाहता हूं, ताकि मैं उन वर्कफ़्लो को नियंत्रित कर सकूं, जिनके माध्यम से कई उपयोगकर्ताओं को बनाने और प्रवाह के माध्यम से चलने के लिए दोनों खातों में प्रवेश करने के बिना कदम बढ़ाया है। हालांकि यह पहली बार है जब मुझे वास्तव में इसका उपयोग करना पड़ा है।
टोनी

4
केवल परीक्षण के बजाय, हम अक्सर डिबग बिल्ड में, अपने आप को एक डिफ़ॉल्ट प्राप्तकर्ता ईमेल सेट करने जैसी चीजों का उपयोग करते हैं, #if DEBUGताकि हम एक सिस्टम का परीक्षण करते समय गलती से दूसरों को स्पैम न करें जो प्रक्रिया के भाग के रूप में ईमेल को प्रसारित करना चाहिए। कभी-कभी ये नौकरी के लिए सही उपकरण हैं :)
कोडिंग किया गया

6
मैं आम तौर पर आपसे सहमत होता हूं लेकिन अगर आप ऐसी स्थिति में हैं, जहां प्रदर्शन सर्वोपरि है, तो आप बाहरी लॉगिंग और उपयोगकर्ता आउटपुट के साथ कोड को अव्यवस्थित नहीं करना चाहते हैं, लेकिन मैं 100% सहमत हूं कि उन्हें कभी भी बदलने के लिए उपयोग नहीं किया जाना चाहिए। मौलिक व्यवहार
माइक

5
-1 इनमें से किसी का भी इस्तेमाल गलत नहीं है। इकाई परीक्षण का दावा करना और DI किसी तरह एक डिबग सक्षम बनाता है एक उत्पाद का निर्माण अनुभवहीन है।
टेड बीघम

15

यह एक उपयोगी हो सकता है:

if (Debugger.IsAttached)
{
...
}

1
व्यक्तिगत रूप से, मैं यह नहीं देखता कि अन्य 2 विकल्पों की तुलना में यह कैसे उपयोगी हो सकता है। यह गारंटी देता है कि पूरे ब्लॉक को संकलित किया गया है, और Debugger.IsAttachedरिलीज बिल्ड में भी रनटाइम पर कॉल किया जाना चाहिए।
जय

9

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

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

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

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

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

@P डैडी: #if DEBUGचारों ओर लपेटने Conditional("DEBUG")से उस फ़ंक्शन के कॉल नहीं हटाए जाते हैं, यह केवल IL से फ़ंक्शन को पूरी तरह से हटा देता है, इसलिए आप अभी भी फ़ंक्शन को कॉल कर रहे हैं जो मौजूद नहीं है (संकलन त्रुटियां)।
मेरा

1
यदि कोई नहीं चाहता कि रिलीज़ में कोड मौजूद हो, तो किसी को "#if DEBUG" में विधि बॉडी को लपेटना चाहिए, संभवतः "#else" स्टब (थ्रो या डमी रिटर्न वैल्यू के साथ), और सुझाव देने के लिए विशेषता का उपयोग करें कि कॉल करने वाले कॉल से परेशान नहीं हैं? यह दोनों दुनिया में सबसे अच्छा लगेगा।
सुपरकट

@ शुक्राणु, @ सुपरकार: हां, आप दोनों सही हैं। मेरी गलती। मैं सुपरकैट के सुझाव के अनुसार संपादन करूंगा।
पी डैडी

5

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

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


2

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

#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

आमतौर पर आपको Program.cs में इसकी आवश्यकता होगी जहां आप या तो डिबग को गैर-डिबग कोड पर चलाने का निर्णय लेना चाहते हैं और वह भी ज्यादातर विंडोज सेवाओं में। इसलिए मैंने एक पठनीय क्षेत्र IsDebugMode बनाया और नीचे दिए गए चित्र के अनुसार स्थिर कंस्ट्रक्टर में इसका मान सेट किया।

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        
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.