C#预处理指令

 

C# 语言的预处理器指令:
#if
#else
#elif
#endif
# define
#undef
#warning
#error
#line
#region
#endregion
#pragma
#pragma warning
#pragma checksum
虽然编译器没有单独的预处理器,但在处理该节中描述的指令时如同存在一个单独的预处理器;这些指令用于辅助条件编译。与 C 和 C++ 指令不同,不能使用这些指令创建宏。
预处理器指令必须是行上的唯一指令。

一、#if
#if 使您可以开始条件指令,测试一个或多个符号以查看它们是否计算为 true。如果它们的计算结果确实为 true,则编译器将计算位于 #if 与最近的 #endif 指令之间的所有代码。例如,
#define DEBUG
// ...
#if DEBUG
    Console.WriteLine("Debug version");
#endif
可以使用运算符 ==(相等)、!=(不相等)、&&(与)及 ||(或)来计算多个符号。还可以用括号将符号和运算符分组。
备注:
使用 #if 以及 #else、#elif、#endif、#define 和 #undef 指令,可以包括或排除基于由一个或多个符号组成的条件的代码。这在编译调试版本的代码或编译特定配置时最为有用。
以 #if 指令开始的条件指令必须用 #endif 指令显式终止。
#define 使您可以定义一个符号,通过将该符号用作传递给 #if 指令的表达式,使该表达式计算为 true。
也可以用 /define 编译器选项来定义符号。可以用 #undef 来取消定义符号。
用 /define 或 #define 定义的符号与具有同一名称的变量不冲突。即,不应将变量名传递到预处理器指令,并且只能用预处理器指令计算符号。
用 #define 创建的符号的范围是在其中定义该符号的文件。
示例
// preprocessor_if.cs
#define DEBUG
#define VC_V7
using System;
public class MyClass
{
    static void Main()
    {
#if (DEBUG && !VC_V7)
        Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && VC_V7)
        Console.WriteLine("VC_V7 is defined");
#elif (DEBUG && VC_V7)
        Console.WriteLine("DEBUG and VC_V7 are defined");
#else
        Console.WriteLine("DEBUG and VC_V7 are not defined");
#endif
    }
}

二、#else
#else 允许您创建复合条件指令,因此,如果前面的 #if 或(可选)#elif 指令中的任何表达式都不为 true,则编译器将计算 #else 与后面的 #endif 之间的所有代码。
备注
#endif 必须是 #else 之后的下一条预处理器指令。

三、
#elif 使您得以创建复合条件指令。如果前面的 #if 和前面的任何 #elif(可选)指令表达式的计算结果都不是 true,则将计算 #elif 表达式。如果 #elif 表达式计算为 true,编译器将计算位于 #elif 和下一个条件指令之间的所有代码。
备注:
#elif 等效于使用:
#else
#if

三、#endif
#endif 指定以 #if 指令开头的条件指令的结尾。

四、#define
使用 #define 可以定义一个符号,并通过将该符号用作表达式传递给 #if 指令,使该表达式的计算结果为 true。例如:

# define DEBUG
符号可用于指定编译的条件。可以使用 #if 或 #elif 来测试符号。还可以使用 conditional 属性执行条件编译。
可以定义符号,但是无法对符号赋值。#define 指令必须在使用任何也不是指令的指令之前出现在文件中。
也可以用 /define 编译器选项来定义符号。可以用 #undef 来取消定义符号。
用 /define 或 #define 定义的符号与具有同一名称的变量不冲突。即,不应将变量名传递到预处理器指令,并且只能用预处理器指令计算符号。
用 #define 创建的符号的范围是在其中定义该符号的文件。

五、#undef
#undef 使您可以取消符号的定义,以便通过将该符号用作 #if 指令中的表达式,使表达式的计算结果为 false。
可以使用 #define 指令或 /define 编译器选项定义符号。在使用任何不是指令的语句之前,必须在文件中使用 #undef 指令。

六、#warning
#warning 使您得以从代码的特定位置生成一级警告。例如:
#warning Deprecated code in this method.
备注:
#warning 通常用在条件指令中。也可以用 #error(C# 参考)生成用户定义的错误。
示例
// preprocessor_warning.cs
// CS1030 expected
#define DEBUG
class MainClass
{
    static void Main()
    {
#if DEBUG
#warning DEBUG is defined
#endif
    }
}

七、#error
#error 使您可以从代码中的特定位置生成错误。例如:
#error Deprecated code in this method.
备注:
#error 通常用在条件指令中。
也可以用 #warning(C# 参考)生成用户定义的警告。
示例
// preprocessor_error.cs
// CS1029 expected
#define DEBUG
class MainClass
{
    static void Main()
    {
#if DEBUG
#error DEBUG is defined
#endif
    }
}

八、#line
#line 使您可以修改编译器的行号以及(可选)错误和警告的文件名输出。下面的示例说明如何报告与行号关联的两个警告。#line 200 指令强迫行号为 200(尽管默认值为 #7)。另一行 (#9) 作为默认 #line 指令的结果跟在通常序列后。
class MainClass
{
    static void Main()
    {
#line 200
        int i;    // CS0168 on line 200
#line default
        char c;   // CS0168 on line 9
    }
}
备注:
#line 指令可能由生成过程中的自动中间步骤使用。例如,如果行从原始的源代码文件中移除,但是您仍希望编译器基于文件中的原始行号生成输出,则可以移除行,然后用 #line 模拟原始行号。
#line hidden 指令对调试器隐藏若干连续的行,这样当开发人员在逐句通过代码时,将会跳过 #line hidden 和下一个 #line 指令(假定它不是另一个 #line hidden 指令)之间的所有行。此选项也可用来使 ASP.NET 能够区分用户定义的代码和计算机生成的代码。尽管 ASP.NET 是此功能的主要使用者,但很可能将有更多的源生成器使用它。
#line hidden 指令不会影响错误报告中的文件名或行号。即,如果在隐藏块中遇到错误,编译器将报告当前文件名和错误的行号。
#line filename 指令指定您希望出现在编译器输出中的文件名。默认情况下,使用源代码文件的实际名称。文件名必须括在双引号 ("") 中。
源代码文件可以具有 #line 指令的任何编号。
示例
下面的示例说明调试器如何忽略代码中的隐藏行。运行此示例时,它将显示三行文本。但是,当设置如示例所示的断点并按 F10 键逐句通过代码时,您将看到调试器忽略了隐藏行。还请注意,即使在隐藏行上设置断点,调试器仍会忽略它。
// preprocessor_linehidden.cs
using System;
class MainClass
{
    static void Main()
    {
        Console.WriteLine("Normal line #1."); //这里设置断点
#line hidden
        Console.WriteLine("Hidden line.");
#line default
        Console.WriteLine("Normal line #2.");
    }
}

九、#region
#region 使您可以在使用 Visual Studio 代码编辑器的大纲显示功能时指定可展开或折叠的代码块。例如:
#region MyClass definition
public class MyClass
{
    static void Main()
    {
    }
}
#endregion
备注:
#region 块必须以 #endregion 指令终止。
#region 块不能与 #if 块重叠。但是,可以将 #region 块嵌套在 #if 块内,或将 #if 块嵌套在 #region 块内。

十、#endregion
#endregion 标记 #region 块的结尾。

十一、#pragma
#pragma 用于给编辑器提供特殊的指令,说明如何编译包含杂注的文件。
#pragma pragma-name pragma-arguments
参数
pragma-name
可识别杂注的名称。
pragma-arguments
杂注特定的参数。

十二、#pragma warning
#pragma warning 可用于启用或禁用某些警告。
#pragma warning disable warning-list
#pragma warning restore warning-list
参数
warning-list
警告编号的逗号分隔列表。只输入数字,不包括前缀 "CS"。
当没有指定警告编号时,disable 禁用所有警告,而 restore 启用所有警告。
示例
// pragma_warning.cs
using System;

#pragma warning disable 414, 3021
[CLSCompliant(false)]
public class C
{
    int i = 1;
    static void Main()
    {
    }
}
#pragma warning restore 3021
[CLSCompliant(false)] // CS3021
public class D
{
    int i = 1;
    public static void F()
    {
    }
}

十三、#pragma checksum
可用于生成源文件的校验和,以帮助调试 ASP.NET 页。
#pragma checksum "filename" "{guid}" "checksum bytes"
参数
"filename"
要求监视更改或更新的文件的名称。
"{guid}"
文件的全局唯一标识符 (GUID)。
"checksum_bytes"
十六进制数的字符串,表示校验和的字节。必须是偶数位的十六进制数。奇数位的数字会导致编译时警告,从而使指令被忽略。
备注:
Visual Studio 调试器使用校验和来确保找到的总是正确的源。编译器计算源文件的校验和,然后将输出发出到程序数据库 (PDB) 文件。最后,调试器使用 PDB 来比较它为源文件计算的校验和。
此解决方案不适用于 ASP.NET 项目,因为算出的是生成的源文件而不是 .aspx 文件的校验和。为解决此问题,#pragma checksum 为 ASP.NET 页提供了校验和支持。
在 Visual C# 中创建 ASP.NET 项目时,生成的源文件包含 .aspx 文件(从该文件生成源文件)的校验和。然后,编译器将此信息写入 PDB 文件。
如果编译器在该文件中没有遇到 #pragma checksum 指令,它将计算校验和,然后将算出的值写入 PDB 文件。
示例
class TestClass
{
    static int Main()
    {
        #pragma checksum "file.cs" "{3673e4ca-6098-4ec1-890f-8fceb2a794a2}" "{012345678AB}" // New checksum
    }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值