在以前寫 MFC 時很習慣的是用 #ifdef _DEBUG 和 #endif 把程式碼包起來,在撰寫 C# 時也很習慣的去查了同樣功能的語法,也就是 #if DEBUG 和 #endif,但這種方法和 #ifdef 有一樣的缺點,如果我們把 Function 包起來,呼叫 Function 的地方沒包到,編譯當然就不會過,如果我們加完某流程後沒有一個一個 Configuration 去做測試,這種狀況往往在跑 CI 時才會被發現,一來一回頗浪費時間。
最近看書學到了一招 System.Diagnostics.ConditionalAttribute
先來看看用 #if #endif 在漏包了 call Function 時的狀況,這種狀況下在 Debug Build 時,前置處理器會將 #if DEBUG 所包起來的部份拿掉,所以最後一行沒有包到的部份就會發生編譯錯誤。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitParams();
#if DEBUG
InitParamsWithDebug();
#endif
InitParamsWithDebug(); // Release 編譯會不過,因為沒有 InitParamsWithDebug 這個 function
}
#if DEBUG
public void InitParamsWithDebug()
{
}
#endif
public void InitParams()
{
}
}
這時我們改用 ConditionalAttribute 來描述 function 的寫法如下,這種方式下,前置處理器會拿掉的不是該 Function,而是 call 此 Function 的部份程式碼,所以在沒有 DEBUG 這個 Symbol 的 Configration 時,被前置處理器移除的是 InitParamsWithDebug(n); 這行,相對的方便許多,也有利於我們將單一功能的程式抽離成為一個獨立的 Function,除此之外, n 這個變數的宣告也會一併被移除,這算是蠻可惜的一點
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitParams();
int n = 0; // Release 編譯完後此行會不見
InitParamsWithDebug(n); // Release 編譯完後此行會不見
n = 9; // 比較可惜的是這行也不見了 XD
}
[Conditional("DEBUG")]
public void InitParamsWithDebug(int i)
{
// Release 編譯完後此 function 依然會存在
}
public void InitParams()
{
}
}
當然,如果我們有多個 Configuration 會執行同一個 Function 或使用某一個 Class 的狀況下,加上多個 Conditional 相當於用 or 串接條件這種做法是可以的,相當的方便,例如
[Conditional("BUILD_FOR_MANUFACTURER_A"), Conditional("BUILD_FOR_MANUFACTURER_B")]
public void ShowManufacturerLogo()
{
}
沒有留言:
張貼留言