第6章 预处理指令
在C#编程语言中包含一组以“#”作为开头的预处理指令。包含预处理指令的语句的作用分成三种,第一种用来描述代码段区间,第二种在指定的条件下忽略代码段,第三种用来报告错误和指定警告的条件。C#编程语言的预处理指令不包含宏,而且必须是当前行中唯一的指令。
6.1 使用region定义代码区间
region语句表示代码块的开始,与之相对的是endregion,这两个语句必须成对出现。在一对redion和endregion之间的代码,可以在VS2008编程环境中使用大纲显示折叠或者展开代码区间,为阅读代码提供极大的方便。
技术要点
本示例主要说明了region预处理指令的使用方法,技术要点如下。
● region除了定义代码区间,通过在编辑器显示大纲的折叠和展开方便阅读代码以外,还具备注释功能,在其后可以跟随代码区间的描述语句。注释语句将被作为region的一部分,不能称为独立的注释语句。而endregion后面可以加入独立的注释语句。
●在region代码区间中可以嵌入if预处理语句,在if预处理语句中也可以嵌入region语句。
实现步骤
(1)创建控制台应用程序项目,命名为“RegionExample”。
(2)打开并编辑Program.cs文件,代码如下所示。
using System; using System.Collections.Generic; using System.Text; namespace RegionExample { class Program { //region表示的代码区间,可以在VS2008编辑器中,按大纲显示折叠或展开代码区间 #region 主程序入口 static void Main(string[] args) { //在region语句后面使用注释,将被作为region语句的一部分 #region 定义变量 int i = 6; #if !DEBUG//在region表示的代码区间可以嵌入#if预处理指令 i++; #endif #endregion//在endregion后面能够使用注释 #if DEBUG//在if预处理指令之间可以嵌入region预处理指令 #region 输出DEBUG编译环境下的结果 Console.WriteLine("DEBUG环境下i的值为:{0}", i); #endregion #endif #if !DEBUG #region 输出非DEBUG编译环境结果 Console.WriteLine("非DEBUG环境下i的值为:{0}", i); #endregion #endif Console.ReadLine(); } #endregion } }
(3)在“Debug”编译环境下,按F5键运行程序,运行结果如下所示。
DEBUG环境下i的值为:6
(4)在“Release”编译环境下,按F5键运行程序,运行结果如下所示。
DEBUG环境下i的值为:7
源程序解读
(1)本示例的region预处理指令语句后面加入了描述性质的语句,作为代码区间的说明。在折叠代码时,能够看到这段代码区间的描述文字。
(2)本示例在region所包含的区间中嵌入了if预处理指令,该指令是一种条件指令,本示例以编程环境作为判断条件,决定if预处理指令所包含的代码段是否执行。
6.2 使用define指令
define预处理指令用于定义一个符号,该符号可用于if预处理指令的判断条件。define预处理指令后定义的符号,在if预处理指令的条件判断表达式中为true。与define预处理相反的指令是undef预处理指令,undef预处理指令用于取消符号的定义,该预处理指令后定义的符号在if预处理指令的条件判断表达式中为false。
技术要点
本示例主要说明了如何在程序中使用define和undef预处理指令,技术要点如下。
● define和undef预处理指令的符号必须位于代码文件的头部所有非指令语句之前。
● 在Debug调试环境下,如果没有undef预处理指令,DEBUG符号为true,当在程序中使用undef声明取消DEBUG定义时,DEBUG符号为false。
实现步骤
(1)创建控制台应用程序项目,命名为“DefineExample”。
(2)打开并编辑Program.cs文件,代码如下所示。
#define USER //定义了USER符号 #undef DEBUG//取消DEBUG符号的定义 using System; using System.Collections.Generic; using System.Text; namespace DefineExample { class Program { static void Main(string[] args) { #if USER//USER已定义 Console.WriteLine("定义了USER符号"); #endif #if !DEBUG//DEBUG未定义,!DEBUG为true Console.WriteLine("未定义DEBUG符号"); #endif Console.ReadLine(); } } }
(3)选择Debug调试环境,按F5键运行程序,运行结果如下所示。
定义了USER符号 未定义DEBUG符号
源程序解读
(1)本示例使用define预处理指令定义一个USER符号,并使用undef预处理指令取消了当前DEBUG符号的定义。在接下来的程序中通过if预处理指令根据符号的定义与否输出结果。
(2)define预处理指令定义的符号,在if预处理指令判断时值为true,undef预处理指令定义的符号,在if预处理指令判断时值为false。在本示例中,DEBUG的值为false,第二个判断使用“!”非运算符,而!DEBUG值为true,输出未定义DEBUG符号的结果。
6.3 使用warning和error指令
实际编程的过程中,程序的错误大致可以分为两种,一种是编程语言的语法错误,这种错误在VS2008的编辑器中,已经得到了很好的识别,而且编译的时候也不能通过。另一种错误是程序算法的错误,这种错误没有错误提示,编译能够顺利完成,这种错误更为隐蔽,更难排除。为了帮助检查和排除第二种程序错误,C#编程语言提供两个用户自定义错误的预处理语句,即warning预处理指令和error预处理指令,当某个条件不符合要求时,提供编译过程的警告信息或编译错误。
技术要点
本示例主要说明warning预处理指令和error预处理指令的使用方法,技术要点如下。
● warning预处理指令在代码的当前位置生成一个警告。在一些特殊的场合中,用来作为比较显眼的警示。
● error预处理指令在代码的当前位置生成一个错误,该预处理指令有效时,程序不能编译执行。
实现步骤
(1)创建控制台应用程序项目,命名为“WarningAndErrorExample”。
(2)打开并编辑Program.cs文件,代码如下所示。
using System; using System.Collections.Generic; using System.Text; namespace WarningAndErrorExample { class Program { static void Main(string[] args) { #if DEBUG//在调试环境中运行程序时,提供一个警告 #warning 程序运行于调试环境下。 Console.WriteLine("DEBUG调试程序"); #endif #if !DEBUG//如果程序不在调试环境中运行,提供一个错误,使程序不能编译执行 #error 本示例程序只能在调试环境下运行 #endif Console.ReadLine(); } } }
(3)在Debug调试环境下按F5键运行程序,运行结果如下所示。
DEBUG调试程序
(4)在Release编译环境下按F5键运行程序,程序编译失败,不能运行。
源程序解读
(1)本示例定义了一个warning预处理指令,在程序中提供一个警告信息,说明程序只能在Debug调试环境下运行。
(2)为了实现代码只能在Debug调试环境下运行,在程序中加入一个id预处理指令的判断,当程序以非Debug调试环境的方式运行时,error指令有效,程序不能编译通过。
6.4 使用条件指令
条件预处理指令指的是以判断条件表达式的计算结果作为是否执行包含在条件指令之间的代码段的依据。条件预处理指令包含一组预处理指令,分别是if预处理指令、elif预处理指令、else预处理指令和endif预处理指令。
技术要点
本示例主要说明了条件预处理指令的使用方法,技术要点如下。
● if预处理指令与endif预处理指令必须成对出现。
● elif预处理指令和else预处理指令,必须位于一对if预处理指令与endif预处理指令之间,而且elif预处理指令必须在else预处理指令之前出现。
● 条件预处理指令是最常用的预处理指令,除了region以外的其他预处理指令都与条件预处理指令有关。常用的方法是根据define和undef预处理指令定义的符号,使用条件指令判断符号的定义情况,当定义有冲突或者不符合规则的时候,根据实际需要提供警告信息,或者禁止编译程序代码。
实现步骤
(1)创建控制台应用程序项目,命名为“IfCommandExample”。
(2)打开并编辑Program.cs文件,代码如下所示。
#define USER//定义USER符号,说明需要进行用户权限校验 #undef DEPARTMENT//定义DEPARTMENT符号,说明需要进行部门权限校验 #define VERIFY//定义是否需要校验的符号 using System; using System.Collections.Generic; using System.Text; namespace IfCommandExample { class Program { static void Main(string[] args) { #if VERIFY//判断是否需要校验 string strMsg = ""; strMsg = Verify(); Console.WriteLine(strMsg); #endif//if预处理指令必须与endif预处理指令成对出现 Console.ReadLine(); } static string Verify() { string Result = ""; #if USER && DEPARTMENT //根据用户和部门符号的定义决定校验方法 Result = "需要同时进行部门及用户校验"; #elif USER//elif预处理语句在if-endif预处理语句之间 Result = "只需要进行用户的校验"; #elif DEPARTMENT//elif预处理语句必须位于else预处理语句之前 Result = "只需要进行部门的校验"; #else #error 未指定任何校验方式 //如果指定了校验符号而未指定校验方式,阻止编译并提供编译错误。 #endif return Result; } } }
(3)按F5键运行程序,运行结果如下所示。
只需要进行用户的校验
源程序解读
(1)本示例定义了三个符号,分别为USER符号、DEPARTMENT符号和VERIFY符号。其中USER符号表示程序需要进行用户权限的校验,DEPARTMENT符号表示程序需要进行部门权限的校验,VERIFY符号表示程序是否需要校验。根据在程序开头部分的定义,可知本程序只需要进行用户权限校验。
(2)本示例程序在主程序入口Main方法中,检查VERIFY符号,判断程序是否需要校验。如果需要校验,则调用Verify方法,并输出校验结果。
(3)在校验方法中,分别对USER符号和DEPARTMENT符号进行检查,判断进行校验的方式。校验方式只能是三种,第一种是只进行用户权限校验;第二种是只进行部门权限校验;第三种,对用户权限和部门权限都进行校验。如果调用了Verify方法而未定义校验符号,则使用error预处理指令阻止编译,并提供错误信息。