概念
指示编译器如何处理源代码
规则
- 预处理指令必须和C#代码在不同的行。
- 与C#语句不同,预处理指令不需要以分号结尾。包含预处理指令的每一行必须以#字符开始。
- 在#字符前可以有空格。
- 在#字符和指令之间可以有空格。
- 允许行尾注释。
- 在预处理指令所在的行不允许分隔符注释。
例
#define PremiumVersion //正确 没有分号
#define BudgetVersion //正确 前面空格
# define MediumVersion //正确 中间空格
#define PremiumVersion /* 注释 */ //错误 不允许分隔符注释(/**/) 行注释可以,也就是//
预处理指令
指令 | 含义概要 |
---|---|
#define identifier | 定义编译符 |
#undef identifier | 取消定义编译符 |
#if expression | 如果表达式是true,编译下面的片段 |
#elif expression | 如果表达式是true,编译下面的片段 |
#else | 如果之前的#if 或#elif 表达式是false,编译下面 |
#endif | 标记为一个#if 结构的结束 |
#region name | 标记一段代码的开始,没有编译效果 |
#endregion name | 标记一段代码的结束,没有编译效果 |
#warning message | 显示编译时的警告消息 |
#error message | 显示编译时的错误消息 |
#line indicator | 修改在编译器消息中显示的行数 |
#pragma text | 指定有关程序上下文的信息 |
#define和#undef指令
声明和取消定义一个编译符号
规则
- 它可以是除了true或false以外的任何标识符,包括C#关键字,以及在C#代码中声明的标识符,这两者都是可以的。
- 它没有值。与C和C++不同,它不表示字符串。
#define
指令声明一个编译符号;#undef
指令取消定义一个编译符号。
例1
#define PremiumVersion
#define EconomyVersion
...
#undef PremiumVersion
#define
和#undef
指令只能用在源文件的第一行,也就是任何C#代码之前使用。在C#代码开始后,#tdefine
和#undef
指令就不能再使用。
例2
using System //C#代码第一行
#define PremiumVersion //错误
namespace Eagle{
#define PremiumVersion //错误
}
编译符号的范围被限制于单个源文件。只要编译符号在任何C#代码之前,重复定义已存在的编译符号也是允许的。
#define AValue
#define BValue
#define AValue //重复定义
条件编译
根据某个编译符号是否被定义标注一段代码被编译或跳过
#if
#else
#elif
endif
条件是一个返回true或false的简单表达式
在#if和#elif指令中使用的条件
参数类型 | 意义 | 运算结果 |
---|---|---|
编译符号 | 使用#define 指令(未)定义的标识符 | True:如果符号已经使用#define 指令定义 Fasle:其它 |
表达式 | 使用符号和操作符!、==、!=、&&、 |
例
#if !DemoVersion //表达式
...
#endif
#if (LeftHanded && OemVersion) //表达式
...
#endif
#if true //下面代码总会被编译
....
#endif
条件编译结构
#if....#endif结构
#if
和#endif
指令在条件编译结构中需要配对使用。只要有#if指令,就必须有配对的#endif。
- 如果
#if
结构中的条件运算结果为true,随后的代码段就会被编译,否则就会被跳过。 - 在
#if...#else
结构中,如果条件运算结果为true,CodeSection1就会被编译,否则,CodeSection2会被编译。
#if Codition
CodeSection1
#elseif
CodeSection2
#endif
#if..#elif结构
#if Cond1
CodeSection1
#elif Cond2
CodeSection2
#elif Cond3
CodeSection3
#endif
- 如果Cond1运算结果为true,CodeSection1就会被编译,然后就会继续编译
#endif
之后的代码; - 否则,如果cond2运算结果为true,CodeSection2就会被编译,然后会继续编译
#endif
之后的代码; - 直到条件运算结果为true或所有条件都返回false,如果这样,结构中没有任何代码段会被编译,会继续编译
#endif
之后的代码。
#if..#elif..#else结构
和#if..#elif
一样方式。只不过没有条件是true的情况下,会编译#else
之后的代码段,然后会继续编译#endif
之后的代码。
#if Cond1
CodeSection1
#elif Cond2
CodeSection2
....
#else
CodeSectionN
#endif
示例
字符串根据定义的编译符号被设置为各种
#define DemoVersionwithoutTimeLimit
...
const int intExpireLength = 30;
string strVersionDesc= null;
int intExpireCount= 0;
#if DemoVersionWithTimeLimit
intExpireCount = intExpirelength;
strVersionDesc = "This version of Supergame Plus will expire in 30 days";
#elif DemoVersionwithoutTimeLimit
strVersionDesc = "Demo Version of Supergame Plus";
#elif OEMVersion
strVersionDesc = "Supergame Plus,distributed under license";
#else
strVersionDesc = "The original Supergame Plus!!";
#endif
Console.writeline( strVersionDesc );
....
诊断指令
诊断指令产生用户自定义的编译时警告及错误消息。
语法
#warning Message
#error Message
Message是字符串,无需引号
示例
#error
指令在#if
结构中,因此只有符合#if
指令的条件时才会生成消息。
#warning
指令用于提醒程序员回头来清理这段代码。
#define RightHanded
#define LeftHanded
#if RightHanded && LeftHanded
#error Can't build for both RightHanded and LeftHanded
#endif
#waring Remember to come back and clean up this code!
行号指令
功能
- 改变由编译器警告和错误消息报告的出现行数;
- 改变被编译源文件的文件名;
- 对交互式调试器隐藏一些行。
语法
#line integer //设置下一行值为整数的行的行号
#line "filename" //设置文件名
#line defaule //重新保存实际的行号和文件名
#line hidden //在断点调试器中隐藏代码
#line //停止在调试器中隐藏代码
#line
指令加上一个整数参数会使编译器认为下面代码的行是所设置的行,之后的行数会再这个行数的基础上递增。
要改变外观文件名,可以在双引号内使用文件名作为参数。双引号是必需的。
要返回真实行号和真实文件名,可以使用default参数。
要对交互调试器的断点调试功能隐藏代码段,可以使用hidden作为参数。要停止隐藏,可以使用不带任何参数的指令。到目前为止,这个功能大多用于在ASP.NET和WPF中隐藏编译器生成的代码。
示例
#line 226
x = y + z; //编译器将执行第226行
...
#line 330 "SourceFile.cs" //改变报告的行号和文件名
var1 = var2 + var3;
#line defaule //重新保存行号和文件名
区域指令
区域指令允许我们标注和有选择性地命名一段代码
特性
- 被放置在希望标注的代码段之上;
- 用指令后的可选字符串文本作为其名字;
- 在之后的代码中必须由
#endregion
指令终止。
示例
在编辑器隐藏代码区域
#region Constructors
MyClass() {
...
}
#endregion
#pragma warning指令
允许我们关闭及重新开启警告消息。
规则
- 要关闭警告消息,可以使用
disable
加上逗号分隔的希望关闭的警告数列表的形式。 - 要重新开启警告消息,可以使用
restore
加上逗号分隔的希望关闭的警告数列表的形式。
示例
#pragma warning disable 618,414 //要关闭的警告消息
.... //列出的警告消息在这段代码中处于关闭状态
#pragma warning restore 618 //要开启的警告消息