预处理就是在编译程序之前由程序处理器对源程序进行一些加工处理工作。C#的预处理类似于C++预处理,但是,与C++不同的是C#没有独立的预处理器,并不是编译器开始编译代码之前的一个单独的处理步骤,它是作为词法分析的一部分来执行的。预处理指令都是以#开头,并且一行只能有一个预处理指令,指令结尾不需要用分号表示语句的结束。
预处理主要有以下几类预处理指令:
◆ #define和#undef:用于定义和取消定义条件编译符号。
◆ #if,#elif,#else和endif:用于按条件跳过源代码中的节。
◆ #error和#warning:发出错误和警告提示。
◆ #region和endregion:显式标记代码中的节。折叠代码。
◆ #line:控制发出错误和警告信息时提供的行号和源文件名称。
预处理指令一般书写格式如下:
◆ 总是以字符#和预处理指令名称开头,占用源代码中的单独一行。#字符的前面以及#字符与指令名称之间可以出现空白。
◆ 包含#define,#undef,#if,#elif,#else,#endif或line指令的源行可以用单行注释结束。在包含预处理指令的源行上不允许使用带分隔符的注释(即/* */样式注释)。
<一> #define、#undef指令
#define和#undef指令是用于定义符号和取消符号定义的预处理指令。格式如下:
#define 符号
#undef 符号
这里定义和取消的符号是DEBUG。如果定义的符号已经存在,#define则不起作用,同样道理,如果符号不存在,#undef也就没有任何作用。#define和#undef指令必须放于源程序的代码之前。如:
#define DEBUG
using System;
#define指令本身没有什么用,但和其它预处理命令结合使用,特别是#if,功能将非常强大。
<二> #if、#elif、#else、#endif指令
#if、#elif、#else、#endif指令被用作条件编译,它们类似于if/else结构。#if和#elif后的标识符表达式可以使用运算符与(&&)、或(||)、非(!)。它们在程序中结构如下所示:
一条#if语句(必须有)
零或多条#elif语句
零或多一条#else语句
一条#endif语句(必须有)
预处理示例:
#define DEBUG
using System;
using System.Collections;
using System.Threading;
namespace 笔记
{
public class MyClass
{
public static void MMain()
{
#if (DEBUG)
Console.WriteLine("DEBUG is defined");
#else
Console.WriteLine("DEBUG is not defined");
#endif
}
}
}
当执行到#if语句时,首先检查DEBUG是否已经定义,如果符号定义,就编译#if块中的代码,否则编译#else块中的代码。
#elif指令相当于“else if”。
#elif指令示例:
#define A
#undef B
using System;
using System.Collections;
using System.Threading;
namespace 笔记
{
public class MyClass
{
public static void MMain()
{
#if (A && !B)
Console.WriteLine("A is defined");
#elif(!A && B)
Console.WriteLine("B is defined");
#elif(A && B)
Console.WriteLine("A and B is defined");
#else
Console.WriteLine("A and B are not define");
#endif
}
}
}
运行结果如下:
A is defined
<三> warning、#error指令
#warning、#error指令用于产生警告或错误。当编译器遇到#warning指令时,会显示#warning后面的文本,编译还会继续进行。当遇到#error指令时,会显示后面的文本,并终止编译退出。这两条指令可以用于检查#define是否定义了什么不正确的符号。
#define DEBUG
#undef RELEASE
using System;
using System.Collections;
namespace 笔记
{
public class MyClass
{
public static void MMain()
{
#if DEBUG
#error 您定义了DEBUG
#endif
#if DEBUG && RELEASE
#warning 你定义了DEBUG和RELEASE
#endif
}
}
}
<四> region、endregion指令
#region、#endregion指令用于标识代码块。即折叠代码
折叠代码如下所示:
这两个指令不会影响编译,而是在一些编译器,如Visual Studio.NET可以将其中的代码折叠和展开,便于浏览和编辑。
<五> #line指令
#line用于修改编译器的行号和错误及警告的文件名输出。使用格式如下:
#line [ 指定行号[“文件名”] | default]
说明如下:
◆ 指定行号:为源代码文件中后面的行指定的编号。
◆ 文件名:可先,希望出现在编译器出中的文件名。缺省时使用源代码文件的实际名称。文件名称必须在双引号(“”0中。
◆ default:重置文件中的行编号。
这一指令一般使用较少。