#if/#endif语句在日常编程中经常会被用到,尤其是想要基于同一份源代码生成不同的编译结果,eg.debug版和release版.但是我们经常遇到的情况是,#if/#endif
成为一种习惯的时候,就会被无限制的滥用,代码进而难以理解或调试。所以,在需要编写条件代码块的时候,提倡使用Conditional特性代替#if条件编译。
#if条件语句
1.#if条件是存在于方法体内的,在方法实现的过程中,对应具体的条件限制,添加检查操作。
public void Func() { string msg = null; #if DEBUG msg = GetDiagnostics(); #endif ... }
在debug版本中,才会执行诊断操作,看起来都很正常,但是往往的结果,却并不是这样。
public void Func() { string msg = null; #if DEBUG msg = GetDiagnostics(); #endif Console.WriteLine(msg); ... }
在release版本中,这样类似的操作是有问题的。
2.#if条件的作用域范围是整个方法体。
public void Func() { #if DEBUG ... #endif }
在debug版本和release版本中都会调用Func方法,虽然在release版本中,Func什么都没有做,但是方法的加载,JIT编译和调用都仍旧是有些开销的。
Conditional特性
来看一个例子
[Conditional("DEBUG")] private void Func() { ... }
Conditional限制了整个方法的调用,无论是否定义了DEBUG环境变量,Func方法都将被编译至程序集中,但是如果没有被调用,Func方法并不会被加载到内存中,也不会被JIT编译。这也是相比于#if,Conditional特性的优势所在。
对于应用多个Conditional特性,一般的关系是“或”
[Conditional("DEBUG"), COnditional("TRACE")] private void Func() { ... }
如果需要“与”的效果,可以自定义符号控制。Conditional特性可以被任何方式定义的符号控制。
#if("DEBUG" && "TRACE") #define BOTH #endif ... [Conditional("BOTH")] private void Func() { ... }
只需要在整个文件头定义自己的符号即可。
Conditional特性只可以应用在整个方法上,并且任何一个使用Conditional特性的方法都只能返回void类型。也就是说,你不能在方法内的代码块上应用Conditional特性,也不可以在有返回值的方法上应用Conditional特性。
综上,使用Conditional特性生成的IL要比使用#if条件更有效率。同时,将其限制在函数层面上,可以更加清晰地将条件性的代码分离出来,从而保证良好的代码结构。