C # if / / directives สำหรับ debug vs release


433

ในคุณสมบัติโซลูชันฉันมีการตั้งค่าคอนฟิเกอเรชันเป็น "ปล่อย" สำหรับโครงการเดียวและของฉัน

ที่จุดเริ่มต้นของรูทีนหลักฉันมีรหัสนี้และจะแสดง "Mode = Debug" ฉันยังมีสองบรรทัดที่ด้านบนสุด:

#define DEBUG 
#define RELEASE

ฉันกำลังทดสอบตัวแปรที่ถูกต้องหรือไม่?

#if (DEBUG)
            Console.WriteLine("Mode=Debug"); 
#elif (RELEASE)
            Console.WriteLine("Mode=Release"); 
#endif

เป้าหมายของฉันคือตั้งค่าเริ่มต้นที่แตกต่างกันสำหรับตัวแปรตามโหมด debug vs release


13
คุณกำลังกำหนดทั้ง debug และ release
Eric Dahlvang

คำตอบ:


719

DEBUG/ _DEBUGควรกำหนดไว้ใน VS แล้ว

ลบ#define DEBUGในรหัสของคุณ ตั้งค่าตัวประมวลผลล่วงหน้าในคอนฟิกูเรชันการบิลด์สำหรับบิลด์เฉพาะ

เหตุผลที่พิมพ์ "Mode = Debug" เป็นเพราะคุณ#defineแล้วข้ามelifไป

วิธีการตรวจสอบที่ถูกต้องคือ:

#if DEBUG
    Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif

RELEASEไม่ตรวจสอบ


77
ฉันต้องการเพิ่มว่าหากใครต้องการตรวจสอบ RELEASE เพียงคนเดียวก็สามารถทำได้: #if! DEBUG

3
ทำไม#ifไม่#ifdef?
Bob Stein

23
@ BobStein-VisiBone อย่าลืมว่าเรามีการพูดคุยเกี่ยวกับ C # นี่ไม่ C. #ifdefเป็นเฉพาะกับ preprocessor ของ C / C ++, C # #ifเอกสารการใช้งานของ
jduncanator

27
@ เจสฉันเชื่อว่านี่คือ Visual Studio ที่ทำตัวเป็นสีเทาไม่ใช่ ReSharper
Dakotah Hicock

1
@DakotahHicock ถูกต้องฉันไม่ได้ใช้ตัวตรวจสอบซ้ำและ VS ทำให้มันเป็นสีเทา
makoshichi

294

โดยค่าเริ่มต้น Visual Studio จะกำหนด DEBUG ถ้าโครงการถูกคอมไพล์ในโหมดดีบั๊กและไม่ได้กำหนดถ้ามันอยู่ในโหมด Release RELEASE ไม่ได้กำหนดไว้ในโหมด Release ตามค่าเริ่มต้น ใช้สิ่งนี้:

#if DEBUG
  // debug stuff goes here
#else
  // release stuff goes here
#endif

หากคุณต้องการทำบางสิ่งเฉพาะในโหมดรีลีส:

#if !DEBUG
  // release...
#endif

นอกจากนี้ยังเป็นการชี้ให้เห็นว่าคุณสามารถใช้แอ[Conditional("DEBUG")]ททริบิวต์กับเมธอดที่ส่งคืนvoidเพื่อให้ทำงานได้เฉพาะเมื่อมีการกำหนดสัญลักษณ์บางอย่าง คอมไพเลอร์จะลบการเรียกทั้งหมดไปยังเมธอดเหล่านั้นหากไม่ได้กำหนดสัญลักษณ์:

[Conditional("DEBUG")]
void PrintLog() {
    Console.WriteLine("Debug info");
}

void Test() {
    PrintLog();
}

6
คำตอบที่ยอดเยี่ยมชื่นชม
Duy Tran

210

ฉันชอบตรวจสอบสิ่งนี้มากกว่ามองหา#defineแนวทาง:

if (System.Diagnostics.Debugger.IsAttached)
{
   //...
}
else
{
   //...
}

ด้วยข้อแม้ที่แน่นอนว่าคุณสามารถรวบรวมและปรับใช้บางอย่างในโหมดดีบัก แต่ก็ยังไม่ได้แนบ debugger


1
ขอบคุณ! ฉันยังไม่รู้ด้วยซ้ำว่า "#defines" นี่คือทางออกที่ยอดเยี่ยม!
ทิม

และในกรณีของฉันนี่คือสิ่งที่ฉันต้องการ ฉันต้องการทราบว่าฉันมีดีบักเกอร์ติดอยู่หรือไม่เพราะฉันรู้ว่าฉันมีรหัสบางส่วนฉันไม่ต้องการดำเนินการหากมีการแนบดีบักเกอร์ นี่มันเจ๋งมาก!
JFTxJ

1
หากเป็นการส่วนตัวที่ชอบใช้#IF DEBUGในสถานการณ์การดีบักรหัสที่ไม่ควรใช้ สำหรับรหัสการผลิตฉันเห็นด้วยกับการใช้ข้างต้น
Coops

10
ข้อสรุปในการทำสิ่งนี้แทนที่จะใช้#DEBUGคือสิ่งนี้ถ้าข้อความอยู่ในรหัสของคุณและตรวจสอบเสมอว่า#DEBUGคำตอบจะลบรหัสที่ไม่สามารถใช้ได้ในเวลาคอมไพล์หรือไม่ดังนั้นคุณจึงไม่ได้ตรวจสอบเวลาทำงานและของคุณ exe (หรืออะไรก็ตามที่คุณคอมไพล์) มีขนาดเล็กลง
ด่าน

1
@ user34660 คำตอบของคำถามที่กล่าวถึงคือ "ไม่" ซึ่งไม่ได้ช่วยใครเลย
สตีฟสมิ ธ

51

ฉันไม่ใช่แฟนตัวยงของ #if โดยเฉพาะอย่างยิ่งถ้าคุณกระจายมันไปทั่วฐานรหัสของคุณเพราะมันจะทำให้คุณเกิดปัญหาเมื่อ Debug builds ผ่าน แต่ Release builds ล้มเหลวหากคุณไม่ระวัง

ดังนั้นนี่คือสิ่งที่ฉันได้มาด้วย (แรงบันดาลใจจาก#ifdef ใน C # ):

public interface IDebuggingService
{
    bool RunningInDebugMode();
}

public class DebuggingService : IDebuggingService
{
    private bool debugging;

    public bool RunningInDebugMode()
    {
        //#if DEBUG
        //return true;
        //#else
        //return false;
        //#endif
        WellAreWe();
        return debugging;
    }

    [Conditional("DEBUG")]
    private void WellAreWe()
    {
        debugging = true;
    }
}

2
เฮ้ตอนนี้มันค่อนข้างสร้างสรรค์ ฉันชอบให้คุณใช้คุณสมบัติเพื่อตั้งค่าคุณสมบัติ
kenchilada

3
นี่เป็นข้อได้เปรียบของการไม่ได้รับผลกระทบจากการ refactoring บั๊กใน Resharper ที่สามารถทำให้โค้ดของคุณยุ่งเหยิงตามการตั้งค่าตามเงื่อนไขปัจจุบัน
Jafin

3
ฉันชอบสิ่งนี้ แต่ฉันสงสัยว่าทำไมไม่สร้างการใช้งานแบบซิงเกิลตันสำหรับบริการนี้แทนที่จะเป็นบริการ เป็นระบบเฉพาะและหยุดคุณไม่ต้องกังวลกับการฉีดทุกที่ (คุณสามารถจินตนาการถึงสถานการณ์ที่การใช้งานฟังก์ชั่นนี้จะแตกต่างกันหรือไม่?
BastanteCaro

1
จริง ๆ แล้วฉันมีซิงเกิลตันและการใช้งานบริการในชั้นเรียนที่ฉันใช้อยู่ตอนนี้เพื่อให้คุณมีทางเลือกในการใช้งาน ... แน่นอนว่าการใช้งานบริการนั้นมีประโยชน์ในการ "ตอ" ออกง่ายกว่า ที่คุณสามารถทดสอบเส้นทางรหัสทั้งสอง ...
ท็อดทอมสัน

ฉันสงสัยว่าทำไมDebuggingServiceไม่เป็นคลาสแบบสแตติกและทำไมคุณต้องมีส่วนต่อประสาน สิ่งนี้เกี่ยวกับการใช้สิ่งนี้กับคอนเทนเนอร์ IoC หรือไม่?
Ben

23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

วิธีการที่มีแอตทริบิวต์เงื่อนไขDebug.Assert DEBUGหากไม่ได้กำหนดไว้การโทรและการมอบหมาย isDebug = trueจะถูกยกเลิก :

หากสัญลักษณ์ถูกกำหนดไว้การโทรจะถูกรวมไว้ มิฉะนั้นการโทร (รวมถึงการประเมินค่าพารามิเตอร์ของการโทร) จะถูกตัดออก

หากDEBUGกำหนดไว้isDebugจะถูกตั้งค่าเป็นtrue(และส่งผ่านไปยังDebug.Assertซึ่งไม่ได้ทำอะไรในกรณีนั้น)


นี่เป็นวิธีที่สร้างสรรค์เช่นกัน :)
แจ็ค

ดี สำหรับตัวแปรการวนซ้ำที่จำเป็นต้องเปลี่ยนระหว่างการดีบักและการเปิดตัว ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
แมตต์เดวิส

19

หากคุณพยายามใช้ตัวแปรที่กำหนดไว้สำหรับชนิดบิลด์คุณควรลบสองบรรทัด ...

#define DEBUG  
#define RELEASE 

... สิ่งเหล่านี้จะทำให้#if (DEBUG)เป็นจริงเสมอ

นอกจากนี้ยังมีไม่ได้เป็นค่าเริ่มต้นเงื่อนไขการรวบรวมสัญลักษณ์สำหรับการปล่อย หากคุณต้องการกำหนดคุณสมบัติของโครงการหนึ่งครั้งให้คลิกที่แท็บสร้างจากนั้นเพิ่ม RELEASE ลงในกล่องข้อความสัญลักษณ์การรวบรวมแบบมีเงื่อนไขภายใต้ทั่วไปหัวข้อ

ตัวเลือกอื่นจะทำเช่นนี้ ...

#if DEBUG
    Console.WriteLine("Debug");
#else
    Console.WriteLine("Release");
#endif

7

ลบคำจำกัดความของคุณที่ด้านบน

#if DEBUG
        Console.WriteLine("Mode=Debug"); 
#else
        Console.WriteLine("Mode=Release"); 
#endif

7

คำตอบโดย Tod Thomson รุ่นแก้ไขเล็กน้อย (bastardized?) เป็นฟังก์ชันแบบสแตติกมากกว่าคลาสแยกต่างหาก (ฉันต้องการเรียกมันใน WebForm viewbinding จากคลาส viewutils ที่ฉันได้รวมไว้แล้ว)

public static bool isDebugging() {
    bool debugging = false;

    WellAreWe(ref debugging);

    return debugging;
}

[Conditional("DEBUG")]
private static void WellAreWe(ref bool debugging)
{
    debugging = true;
}

6

ให้แน่ใจว่าได้กำหนดค่าคงที่ DEBUG ในคุณสมบัติ Project Build #if DEBUGนี้จะช่วยให้ ฉันไม่เห็นค่าคงที่ RELEASE ที่กำหนดไว้ล่วงหน้าดังนั้นจึงอาจบอกเป็นนัยได้ว่าสิ่งใดก็ตามที่ไม่ได้อยู่ในบล็อก DEBUG คือโหมด RELEASE

กำหนดค่าคงที่ DEBUG ในคุณสมบัติสร้างโครงการ


5

NameSpace

using System.Resources;
using System.Diagnostics;

วิธี

   private static bool IsDebug()
    {
        object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);
        if ((customAttributes != null) && (customAttributes.Length == 1))
        {
            DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute;
            return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled);
        }
        return false;
    }

3

เคล็ดลับที่อาจช่วยคุณประหยัดเวลาได้มาก - อย่าลืมว่าแม้ว่าคุณจะเลือกdebugภายใต้การกำหนดค่าการสร้าง (บน vs2012 / 13 เมนูมันอยู่ภายใต้ BUILD => ผู้จัดการการกำหนดค่า) - ไม่เพียงพอ

คุณต้องให้ความสนใจกับ PUBLISH Configurationเช่น:

ป้อนคำอธิบายรูปภาพที่นี่


0

เนื่องจากจุดประสงค์ของคำสั่งคอมไพเลอร์เหล่านี้คือการบอกคอมไพเลอร์ว่าไม่ต้องรวมรหัส, รหัสการดีบัก, รหัสเบต้าหรือรหัสที่ผู้ใช้ปลายทางของคุณต้องการยกเว้นว่าฝ่ายโฆษณาคือ #Define AdDept ที่คุณต้องการ สามารถรวมหรือลบออกตามความต้องการของคุณ โดยไม่ต้องเปลี่ยนซอร์สโค้ดของคุณหากตัวอย่างเช่น AdDept ที่ไม่ใช่ผสานเข้ากับ AdDept จากนั้นสิ่งที่ต้องทำคือการรวม #AdDept directive ในหน้าคุณสมบัติตัวเลือกคอมไพเลอร์ของเวอร์ชันที่มีอยู่ของโปรแกรมและทำการคอมไพล์และ wa la! โค้ดของโปรแกรมที่รวมกันนั้นมีอยู่จริง!

คุณอาจต้องการใช้การประกาศสำหรับกระบวนการใหม่ที่ไม่พร้อมสำหรับเวลาที่ใช้งานมากหรือที่ไม่สามารถใช้งานได้ในรหัสจนกว่าจะถึงเวลาที่จะเผยแพร่

อย่างไรก็ตามนั่นคือวิธีที่ฉันทำ


0

ฉันต้องคิดเกี่ยวกับวิธีที่ดีกว่า มันเริ่มขึ้นเมื่อฉันว่า # หากบล็อกเป็นความคิดเห็นที่มีประสิทธิภาพในการกำหนดค่าอื่น ๆ (สมมติว่าDEBUGหรือRELEASE; แต่จริงด้วยสัญลักษณ์ใด ๆ )

public class Mytest
    {
        public DateTime DateAndTimeOfTransaction;
    }

    public void ProcessCommand(Mytest Command)
        {
            CheckMyCommandPreconditions(Command);
            // do more stuff with Command...
        }

        [Conditional("DEBUG")]
        private static void CheckMyCommandPreconditions(Mytest Command)
        {
            if (Command.DateAndTimeOfTransaction > DateTime.Now)
                throw new InvalidOperationException("DateTime expected to be in the past");
        }

0

ลบนิยามและตรวจสอบว่าเงื่อนไขอยู่ในโหมดดีบักหรือไม่ คุณไม่จำเป็นต้องตรวจสอบว่าคำสั่งที่อยู่ในโหมดการเปิดตัว

บางสิ่งเช่นนี้

#if DEBUG
     Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.