《Effective C#》读书笔记——条目4:使用Conditional特性而不是#if条件编译<C#语言习惯>

简介:

  #if/#endif 语句常用来基于同一份源码生成不同的编译结果,其中最常见的就是debug版和release版。但是这些工具在实际应用中并不是非常友好,因为它们容易被滥用,其代码页进而难以理解或调试。C#设计中考虑到这个问题,并提供了更好的工具——Conditional特性,用来为不同的环境编译不同的机器码。Conditional特性适用于方法的层面,这将强制我们将条件代码拆分为独立的方法。在需要编写条件代码时,我们应该使用Conditional特性来替代#if/#endif。

 

使用#if/#endif 语句的缺点

  例如编写一个私有方法来获取调用它的函数名称:

复制代码
 1         private string CheckMethod()
 2         {
 3 
 4 #if DEBUG
 5             Trace.WriteLine("Entering CheckState for Person");
 6 
 7             string methodName = new StackTrace().GetFrame(1).GetMethod().Name;
 8 
 9             return methodName;
10 #endif
11             return null;
12         }
复制代码

条件编译#if和#endif将会在最终release版本中留下一个名为CheckMethod()的空方法,但它在release版和debug版中都将被调用,虽然在release版本中CheckMethod()什么也不做,但是方法的加载、JIT编译和调用仍旧有些开销。而且这也容易引入一些问题:

复制代码
1         public void Func()
2         {
3             string msg = null;
4 
5 #if DEBUG
6             msg = "Debug";
7 #endif
8             Console.WriteLine(msg);
9         }
复制代码

这段代码在Debug版本中不会有问题,但是在release版本中就会输出一个空行,出错的原因是因为我们把属于主程序的逻辑和条件编译的逻辑混合在一起了。在源代码中随意使用#if和#endif将让你很难诊断出不同版本之间的差异。

 

更好的解决办法——使用Conditional特性

  为了避免出现上面的问题我们可以使用Conditional特性。使用Conditional特性即可将一些函数拆分出来,让其只有在定义了某些环境变量或者设置了某个值之后才能编译并成为类的一部分。Conditional特性最常用的地方就是讲一段代码变成调试语句。使用Conditional特性的隔离策略要比#if/#endif不容易出错。

看下面的代码:

复制代码
1          [Conditional("DEBUG")]
2         private void CheckMethod()
3         {
4             Trace.WriteLine("Entering CheckState for Person");
5             string methodName = new StackTrace().GetFrame(1).GetMethod().Name;
6         }
复制代码

无论是否定义了DEBUG环境变量,CheckMethod()方法都将被编译到程序集中。但是如果没有被调用,CheckMethod()方法并不会被加载到内存中,也不会被JIT编译。这其实也揭示了C#编译器的编译过程与JIT编译座次之间的区别。

 

Conditional特性的限制

Conditional特性只可以应用在整个方法上。

任何使用了Conditional特性的方法都只能返回void类型。

 

小节:

综上所述,使用Conditional特性生成的IL要比使用#if/#endif时更有效率。同时,将其限制在函数层面上可以更清晰的将条件性代码分离出来,以便进一步保证代码的良好结构。此外C#编译器也为此提供良好的支持,从而避免了以前使用#if/#endif时常犯的错误。与预处理指令相比,Conditional特性让我们可以更好地将条件性代码分离开来。

 

阅读书目:《Effective C#》

本文转自gyzhao博客园博客,原文链接:http://www.cnblogs.com/IPrograming/archive/2012/08/21/Effective_CSharp_04.html ,如需转载请自行联系原作者
相关文章
|
1月前
|
C#
C#学习相关系列之数据类型类的三大特性(二)
C#学习相关系列之数据类型类的三大特性(二)
|
3月前
|
编译器 C# 开发者
C# 11.0中的新特性:覆盖默认接口方法
C# 11.0进一步增强了接口的灵活性,引入了覆盖默认接口方法的能力。这一新特性允许类在实现接口时,不仅可以提供接口中未实现的方法的具体实现,还可以覆盖接口中定义的默认方法实现。本文将详细介绍C# 11.0中接口默认方法覆盖的工作原理、使用场景及其对现有代码的影响,帮助开发者更好地理解和应用这一新功能。
|
3月前
|
编译器 C# 开发者
C# 9.0中的顶级语句:简化程序入口的新特性
【1月更文挑战第13天】本文介绍了C# 9.0中引入的顶级语句(Top-level statements)特性,该特性允许开发者在不使用传统的类和方法结构的情况下编写简洁的程序入口代码。文章详细阐述了顶级语句的语法、使用场景以及与传统程序结构的区别,并通过示例代码展示了其在实际应用中的便捷性。
|
API C#
C#反射与特性(三):反射类型的成员
C#反射与特性(三):反射类型的成员
249 0
|
3月前
|
开发框架 .NET Java
ASP.NET Core高级编程--C#基本特性(一)
本文章简略介绍C#的部分特性
|
5月前
|
C#
c#之Attribute特性的原理
c#之Attribute特性的原理
23 0
|
9月前
|
数据可视化 程序员 C#
C# 面向对象三大特性
C# 面向对象三大特性
68 0
|
缓存 IDE API
C#反射与特性(五):主类型成员操作
C#反射与特性(五):主类型成员操作
337 0
C#反射与特性(五):主类型成员操作
|
C# 图形学
C#——特性
C#——特性
53 0
|
开发框架 .NET C#
C#版本与. NET版本对应关系以及各版本的特性
C#版本与. NET版本对应关系以及各版本的特性
442 0