Preprocessor Directives สำหรับ Debug/Release Build ใน C#
C# ใช้ Preprocessor Directives (ขึ้นต้นด้วย #) เพื่อควบคุมการคอมไพล์โค้ดตาม Build Configuration (Debug/Release)
Build Configuration ใน Visual Studio
- Debug - ใช้สำหรับ Debugging มี Symbol (PDB), ไม่ Optimize, Define
DEBUGและTRACE - Release - Build สำหรับ Production Optimize โค้ด, Define
TRACEเท่านั้น
เปลี่ยน Configuration: Toolbar → Dropdown (Debug/Release) หรือ Build → Configuration Manager
Syntax พื้นฐาน
#if DEBUG
// โค้ดนี้คอมไพล์เฉพาะ Debug build
Console.WriteLine("Debug mode");
#else
// โค้ดนี้คอมไพล์เฉพาะ Release build (และไม่ใช่ DEBUG)
Console.WriteLine("Release mode");
#endif
Directives ที่เกี่ยวข้อง
| Directive | คำอธิบาย |
|---|---|
#if SYMBOL | คอมไพล์ถ้า SYMBOL ถูก Define |
#elif SYMBOL | Else-if สำหรับ #if |
#else | กรณี #if เป็น false |
#endif | ปิด #if (บังคับ) |
#define SYMBOL | Define Symbol (ต้องอยู่บนสุดไฟล์) |
#undef SYMBOL | Undefine Symbol |
#warning "msg" | แสดง Warning ตอน Build |
#error "msg" | แสดง Error หยุด Build |
ตัวอย่างการใช้งาน
1. Basic Debug/Release
using System;
class Program
{
static void Main()
{
#if DEBUG
Console.WriteLine("Mode = Debug");
Console.WriteLine("Connection: Server=dev-db;Database=MyApp;");
#else
Console.WriteLine("Mode = Release");
Console.WriteLine("Connection: Server=prod-db;Database=MyApp;");
#endif
Console.ReadLine();
}
}
Output (Debug): Mode = Debug | Output (Release): Mode = Release
2. Logging/Diagnostics เฉพาะ Debug
public class OrderService
{
private readonly ILogger _logger;
public void ProcessOrder(Order order)
{
#if DEBUG
_logger.LogDebug("Processing order {OrderId} with items: {@Items}",
order.Id, order.Items);
#endif
// Business logic...
#if DEBUG
_logger.LogDebug("Order {OrderId} completed", order.Id);
#endif
}
}
3. Custom Symbol (Define เอง)
// ใน .csproj หรือ Project Properties → Build → Conditional compilation symbols
// DEBUG;TRACE;MY_FEATURE
public class FeatureService
{
public void DoWork()
{
#if MY_FEATURE
Console.WriteLine("Feature Enabled!");
#else
Console.WriteLine("Feature Disabled");
#endif
}
}
4. ConditionalAttribute (ทางเลือกที่ดีกว่าสำหรับ Method)
using System.Diagnostics;
public class Logger
{
// Method นี้จะถูก Remove ออกจาก IL ถ้าไม่ได้ Define DEBUG
// เรียกได้แต่ใน Debug build
[Conditional("DEBUG")]
public void LogDebug(string message)
{
Console.WriteLine($"[DEBUG] {message}");
}
[Conditional("TRACE")]
public void LogTrace(string message)
{
Console.WriteLine($"[TRACE] {message}");
}
}
ข้อดีของ ConditionalAttribute:
- โค้ดเรียก Method ยังคงอยู่ แต่ Method body ถูกลบออก (No IL)
- ไม่ต้อง wrapping #if ทุกครั้งที่เรียก
- Argument evaluation ก็ถูก skip ด้วย (ประหยัด performance)
Predefined Symbols
| Symbol | ความหมาย |
|---|---|
DEBUG | Debug build (Define โดย Default) |
TRACE | Debug และ Release (Define โดย Default) |
NETFRAMEWORK | Target .NET Framework |
NETCOREAPP | Target .NET Core |
NETSTANDARD | Target .NET Standard |
NET6_0, NET7_0, NET8_0 | Target Framework Version เฉพาะ |
Multi-targeting Example
public class PlatformService
{
public string GetPlatformInfo()
{
#if NETFRAMEWORK
return ".NET Framework";
#elif NETCOREAPP
return ".NET Core / .NET 5+";
#elif NETSTANDARD
return ".NET Standard";
#else
return "Unknown";
#endif
}
}
Best Practices
| Do | Don't |
|---|---|
| ใช้ #if DEBUG สำหรับ Logging/Diagnostics | ใช้ #if เยอะจนโค้ดอ่านยาก |
| ใช้ [Conditional("DEBUG")] สำหรับ Method | Wrap Logic ทั้ง Method ด้วย #if |
| Define Custom Symbol ใน .csproj | Define Symbol ในไฟล์โค้ด (#define) |
| Comment ให้ชัดเจน ว่าทำไมถึง #if | ทิ้ง #if ไว้โดยไม่มีคำอธิบาย |
สรุป
#if DEBUG ... #else ... #endifควบคุมการคอมไพล์ตาม Build Config- DEBUG Define ใน Debug build, TRACE Define ในทั้งคู่
- ใช้
[Conditional("DEBUG")]สำหรับ Method Logging - สะดวกกว่า - Custom Symbol 定義在 .csproj (
<DefineConstants>) - Release build: โค้ดใน #if DEBUG ถูกลบออกจาก Assembly เลย (Zero overhead)