下面对C#中的预编译指令进行介绍:
1.#define和#undef
用法:
#define DEBUG
#undef DEBUG
#define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量,但是它没有具体的值,可以将它看为一个符号而已。#undef就是删除这个符号的定义。如果符号DEBUG没定义过,则#undef不起作用,否则#define不起作用。二者都必须放在源代码之前。二者的顺序看代码的顺序:
#define DEBUG
#undef DEBUG
这样的话,DEBUG是没有定义的,如果二者换个顺序,编译器就认为DEBUG被定义了
2.#if、#elif、#else、#endif
这个告诉编译器进行编译代码的流程控制。考虑下面代码:
#if DEBUG
Console.Write("debug");
#elif RELEASE
Console.Write("release");
#else
Console.Write("other");
#endif
以上代码就是说如果定义了DEBUG则输出debug,定义了RELEASE,则输出realse,否则输出other。如果定义了DEBUG和REALSE会怎么样呢?各位可以自己试一下。
3.#warning、#error
通过这两个指定可以告诉编译器,出一个警告还是错误信息。除了错误信息以后,编译将停止。
参考下面的代码(C#在Debug状态下自动定义DEBUG标志,但Release状态不会自动定义RELEASE标志):
#if DEBUG
#warning 现在是Debug状态
#elif RELEASE
#warning 现在是Release状态
#else
#error 并清楚什么状态
#endif
4.#region 和#endregion
这个两个用来组成代码块。
5.#line
这个指令可以改变编译器在警告和错误信息中显示的文件名和行号信息,用#line default把行号恢复为默认的行号。
#line [ number ["file_name"] | default ]
number
要为源代码文件中后面的行指定的编号。
"file_name"(可选)
希望出现在编译器输出中的文件名。默认情况下,使用源代码文件的实际名称。文件名必须括在双引号 ("") 中。
default
重置文件中的行编号。
备注:
#line 可能由生成过程中的自动中间步骤使用。例如,如果中间步骤从原始的源代码文件中移除行,但是您仍希望编译器基于文件中的原始行号生成输出,则可以移除行,然后用 #line 模拟原始行号。
下面的示例说明如何报告与行号关联的两个警告。#line 200 指令迫使行号为 200(尽管默认值为 #7)。另一行 (#9) 作为默认 #line 指令 的结果跟在通常序列后。
示例1:
// preprocessor_line.cs
public class MyClass2
{
public static void Main()
{
#line 200
int i; // line 200
#line default
char c; // line 9
}
}
示例2:
下面的示例说明调试器如何忽略代码中的隐藏行。运行此示例时,它将显示三行文本。但是,当设置如示例所示的断点并按 F10 键逐句通过代码时,您将看到调试器忽略了隐藏行。另请注意,即使在隐藏行上设置断点,调试器仍会忽略它。
// preprocessor_linehidden.cs
using System;
class MyClass
{
public static void Main()
{
Console.WriteLine("Normal line #1."); // Set a break point here.
#line hidden
Console.WriteLine("Hidden line.");
#line default
Console.WriteLine("Normal line #2.");
}
}
6.#pragma
可以抑制或恢复指定的编译警告。与命令行选项不同,#pragma指令可以在类和方法上执行,对抑制什么警告和抑制的时间进行更精细的控制。
#pragma warning disable 169
public class Aclass
{
int nFiled;
}
#pragma warning restore 169
出处:http://blog.sina.com.cn/s/blog_6ae1dc950100nf3f.html
======================================================================================
C#的预处理器指令很容易识别,你看到了#,就能认出它们。
它和其他的命令有什么区别呢?
区别在于这些命令从来不会转化为可执行代码的命令,但是会影响编译过程的各个方面。
它用来做什么呢?
当计划发布两个版本的代码的时候。即基本版和拥有更多版本的企业版,就可以用到预处理器指令。
在编译基本版的时候,使用预处理指令会禁止编译器编译与额外功能相关的代码。
另外,在编写提供调试信息的代码时,也可以使用预处理器指令。
下面介绍预处理器指令的功能:
#define和#undef
#define用法: #define Debug
Debug可以看做是声明的一个变量,但此变量没有真正的值,仅存在。
#define单独用没什么意义,一般是和#if结合使用。
#undef用法: #undef Debug
作用就是删除Debug的定义。如果Debug符号不存在,这条指令就没有任何作用。如果Debug符号存在,则之前的#define就没有作用。
#define与#undef声明必须放在C#源文件的开头位置,即程序集的引用的上方。
#if,#elif,#else和#endif
下面来看一个例子
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
//#define DebugA #define DebugB using System; namespace MyApplication { class Program { static void Main(string[] args) { #if DebugA Console.WriteLine("Hello DebugA"); #elif DebugB Console.WriteLine("Hello DebugB"); #else Console.WriteLine("Hello Debugelse"); #endif } } }
#elif(=else if)和#else指令可以用在#if中,和C#中的if,else if,else含义相同。
#if和#elif支持一组逻辑运算符"!","==","!="和"||",如果符号存在,则为true。
#if DebugB && DebugA //当Debug与DebugA同时存在才会执行
#warning和#error
当编译器遇到这两条指令时,会分别产生警告和错误。如果编译器遇到#warning指令,会显示该指令后的文本,之后继续编译。
如果遇见#error指令,也会显示指令后面的文本。但会立刻退出编译,不会产生IL代码。(其实和编译器的警告和错误意义相同)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
static void Main(string[] args) { #warning "All Right?" Console.WriteLine("Contine..."); //#error "All Right?" // Console.WriteLine("Contine..."); }
下图为放开#error注释:
#region和#endregion
这两条指令,大家应该非常熟悉,作用就是代码缩进和指定该代码块的名称,使得代码可以更好的布局。详细用法可以参照报表系列的代码。
#line
这条指令很少用到。作用就是:如果代码在编译之前,要使用某些软件包改变输入的代码,就可以使用它。
(其实就是更改代码的行号)
#pragma warning
此指令可启用或禁用某些警告。
用法: #pragma warning disable warning-list
#pragma warning restore warning-list
例子:
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" 十六进制数的字符串,表示校验和的字节。必须是偶数位的十六进制数。
奇数位的十六进制数字会导致编译时警告,然后指令被忽略。
例子:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class TestClass { static int Main() { #pragma checksum "file.cs" "{3673e4ca-6098-4ec1-890f-8fceb2a794a2}" "{012345678AB}" // New checksum } }
出处:http://www.cnblogs.com/ck-winner/archive/2013/02/05/2892756.html
===================================================================================
重要说明:
预处理指令都以#号开头并位于行首前面可以出现空格符。
- #define DEBUG
- #define ISSAY
![](http://static.blog.csdn.net/images/save_snippets_01.png)
上面的语句定义了连个个预编译的符号,他的作用域是他所处整个文件,定义符号的语句必须出现在所有代码之前, 否则编译的时候会出现一个异常: 不能在文件的第一个标记之后,定义或取消定义预处理器符号 。我们也可以使用#undef来取消一个符号的定义,来看个例子。
#define DEBUG #undef DEBUG #define ISSAY using System; namespace JustDoIt { class Program { static void Main(string[] args) { #if DEBUG Console.Write("debug."); #endif #if ISSAY Console.Write("hello."); #else Console.Write("you can say nothing."); #endif Console.ReadLine(); } } } //输出:hello
==============================================================================================
C#有许多名为预处理器指令的命令。这些命令从来不会被翻译为可执行代码中的命令,但会影响编译过程的各个方面。例如,预处理器可禁止编译器编译代码的某一部分。如果计划发布两个版本的代码,比如基本版本和企业版本,或者针对不同的.NET Framework版本进行编码,就可以使用这些指令。在Anthem.NET的代码中我们经常可以看到这种用法。
预处理器指令的开头都有符号#。
注意:
C#中并没有一个像C++那样的独立预处理器,所谓的预处理器指令仍由编译器处理。
下面将对这些指令逐一介绍。
1. #define和#undef
#define可以定义符号。当将符号用作传递给#if指令的表达式时,此表达式的计算结果true。如
#define DEBUG
它告诉编译器存在给定名称的符号,在本例中是DEBUG。这个符号不是实际代码的一部分,只在编译代码时存在。
#undef正好相反,它删除一个符号。
必须把#define和#undef命令放在C#源码的开头,即在要编译的任何代码之前。它不像C++中那样可以定义常数值。
#define本身并无大用,它需要配合#if指令使用。
如下代码:
#define DEBUG int DoSw(double x) { #if DEBUG COnsole.WriteLine("x is"+X); #edif }
2. #if, #elif, #else和#endif
这些指令告诉编译器是否要编译某个代码块。看下面的方法:
static void PrintVersion() { #if V3 Console.WriteLine("Version 3.0"); #elif V2 Console.WriteLine("Version 2.0"); #else Console.WriteLine("Version 1.0"); #endif }
上面的代码会根据定义的符号来打印不同的版本信息。 这种方式成为条件编译。
注意:
使用#if不是条件编译代码的唯一方式,C#还提供了通过Conditional属性的机制。
#if和#elif还支持一组逻辑运算符!=,==,!=和|| 。如果符号存在,符号的值被认为是true,否则为false,如:
#if V3 || (V2 == true) // if 定义了V3或V2符号...
3. #warning和#error
这也是两个很有用的预处理器指令,编译器遇到它们时,会分别产生警告或错误信息。如果遇到#warning指令,会向用户显示#warning指令后面的文本。实际上,在VS2005中,IDE会直接将信息标识出来:
而如果编译器遇到#error,就会立即退出编译,不会产生IL代码。
使用这两个指令可以检查#define是不示做错了什么事,使用#warning可以让自己想起做什么事。
#if DEBUG && RELEASE #error "You 've define xxxx!" #ednif #warning "Don't forgot to removexxxxxx!" Console.WriteLine("I have this job");
4. #region和#endregion
#region和#endregion指令用于把一段代码标记为有指定名称的一个块,如下所示:
#region private methods private int x; private int y; #endregion
这两个指令不会影响编译过程。但可以为VS编辑器所识别,从而使得代码显示布局更为清晰。
5. #line
可以用于改变编译器在警告和错误信息中显示的文件的名字和行号信息。如果编写代码时,在把代码发给比编译器前,要使用某些软件包改变键入的代码,玖可以使用者个指令,因为这意味着比编译器的报告的行号或文件名与文件中的行号或编译的文件名不匹配。#line指令可以用于恢复这种匹配也可以使用语法#line default 把行号恢复默认。
#line 164 "cORE.CS"
#LINE default
6. #pragma,#pragma warning,#pragma checksum
#pragma:为编译器提供特殊的指令,说明如何编译包含杂注的文件。
#pragma warning:可启用或禁用某些警告。
#pragma checksum:生成源文件的校验和,以帮助调试ASP.NET页。
可以抑制或恢复指定的编译警告。与命令行选项不同,#pragma指令可以在类和方法上执行,对抑制什么警告和抑制的时间进行更精细的控制。
#pragma warning disable 169 public class Aclass { int nFiled; }
#pragma warning restore 169
这些预处理指令详见MSDN:
出处:http://www.bianceng.cn/Programming/csharp/200910/11700.htm