首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

Effective C# 原則 4:以條件屬性取代 #if 編譯指示區塊

     編輯:關於C#

#if/#endif 易被濫用,導致程式碼難讀、難除錯、不同建構配置行為不一致。C# 提供條件屬性([Conditional("SYMBOL")]),針對方法啟用/停用呼叫,結構清晰、編譯器最佳化、避免常見陷阱。

傳統 #if 缺陷範例

// 錯誤:DEBUG 時 msg 賦值,RELEASE 時 msg 為 null → 輸出空行
string msg = null;
#if DEBUG
msg = GetDiagnostics();
#endif
Console.WriteLine(msg); // RELEASE 輸出空行,非預期行為

散落的 #if 讓邏輯支離破碎,除錯時需心理模擬不同配置下的程式碼。

Conditional 屬性機制

[Conditional("DEBUG")]
private void CheckState()
{
    var method = new StackTrace().GetFrame(1).GetMethod().Name;
    Debug.Assert(_lastName != null, method, "Last Name cannot be null");
    Debug.Assert(_lastName.Length > 0, method, "Last Name cannot be blank");
    Trace.WriteLine($"CheckState for Person: called by {method}");
}

// 呼叫端:
public string LastName
{
    get { CheckState(); return _lastName; }
    set { CheckState(); _lastName = value; CheckState(); }
}

編譯器行為

  • DEBUG 定義:保留 CheckState() 呼叫,方法本體編譯進組件。
  • DEBUG 未定義:移除所有呼叫點,方法本體仍編譯進組件但不載入記憶體、不 JIT 編譯(除非被呼叫)。

相當於:

// DEBUG 定義時
get { CheckState(); return _lastName; }
// DEBUG 未定義時
get { return _lastName; }

多條件與邏輯組合

  • OR 關係:多個 [Conditional] 屬性並列。[Conditional("DEBUG"), Conditional("TRACE")] → 任一定義即啟用。
  • AND 關係:需自行定義組合符號。
    
    #if DEBUG && TRACE
    #define BOTH
    #endif
    [Conditional("BOTH")]
    void Method() { ... }

限制與規範

  • 僅適用於回傳 void 的方法。
  • 不可套用於方法內程式碼區塊、屬性、建構函式、非 void 方法。
  • 方法不得有副作用(修改狀態、回傳值),否則移除呼叫會改變程式語意。
  • 標準庫 Debug.Assert、Trace.WriteLine 皆以此機制實作。

優勢總結

最佳實務

  • 診斷、斷言、效能計數、日誌記錄等輔助性功能,全面改用 [Conditional]。
  • 將條件邏輯封裝於專用方法,呼叫端保持乾淨。
  • 符號定義:專案屬性 → Build → Conditional compilation symbols、或命令列 /define:SYMBOL。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
面向#if/#endifConditional Attribute
程式碼結構碎片化、巢狀難讀方法層級、結構清晰
編譯器檢查無法檢查邏輯一致性強制 void 回傳、無副作用
IL 體積殘留死碼移除呼叫指令,方法本體保留但不 JIT
除錯體驗需心理模擬多配置原始碼單一版本,設定符號即可