下面對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
下面來看一個例子

//#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代碼。(其實和編譯器的警告和錯誤意義相同)

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" 十六進制數的字符串,表示校驗和的字節。必須是偶數位的十六進制數。
奇數位的十六進制數字會導致編譯時警告,然后指令被忽略。
例子:

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
上面的語句定義了連個個預編譯的符號,他的作用域是他所處整個文件,定義符號的語句必須出現在所有代碼之前, 否則編譯的時候會出現一個異常: 不能在文件的第一個標記之后,定義或取消定義預處理器符號 。我們也可以使用#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