C# 編譯器在正式編譯前,先由預處理器處理以 # 開頭的指令:條件編譯、符號定義、錯誤警告、程式碼區塊摺疊、行號控制等。注意:C# 無巨集替換功能,#define 僅定義條件編譯符號,不具備 C/C++ 的文字替換能力。
| 指令 | 用途 | 範例 |
|---|---|---|
#define SYMBOL | 定義條件編譯符號(必須在檔案最前端) | #define DEBUG |
#undef SYMBOL | 取消符號定義 | #undef DEBUG |
#if / #elif / #else / #endif | 條件編譯區塊 | 見下文 |
#warning "msg" | 編譯時輸出警告,不中斷建置 | #warning "此功能即將棄用" |
#error "msg" | 編譯時輸出錯誤,中斷建置 | #error "不支援的目標框架" |
#region / #endregion | IDE 程式碼摺疊區塊(不影響編譯) | #region 初始化 ... #endregion |
#line number ["file"] | 修改編譯器報告的行號/檔名 | #line 200 "Generated.cs" |
#line hidden | 隱藏行號,偵錯時略過(用於產生器輸出) | 見下文 |
#pragma warning | 控制特定警告編號啟用/停用 | #pragma warning disable CS0168 |
#pragma checksum | 為偵錯器提供檔案檢查碼(ASP.NET Razor 等用) | 少見 |
#define DEBUG // 檔案層級定義,專案層級建議在「建置」→「條件編譯符號」設定
#if DEBUG
Console.WriteLine("Debug 模式:啟用詳細日誌");
#elif RELEASE
Console.WriteLine("Release 模式:效能優化");
#elif TESTING
Console.WriteLine("測試模式:Mock 服務");
#else
Console.WriteLine("未知建置配置");
#endif
最佳實務:不要在原始碼中寫 #define DEBUG,改在專案屬性 → Build → Conditional compilation symbols 設定 DEBUG;TRACE(Debug)或 TRACE(Release),由 MSBuild 自動注入,避免檔案間不一致。
#if NETFRAMEWORK
// .NET Framework 專用 API
using System.Web;
#elif NETCOREAPP
// .NET Core / .NET 5+ 專用
using Microsoft.AspNetCore.Http;
#elif NETSTANDARD2_0
// .NET Standard 2.0 相容層
#endif
當使用 T4、Source Generator、Razor 等產生 C# 程式碼時,編譯錯誤行號會指向產生的檔案,難以對應原始模板。#line 可修正此問題:
// 產生器輸出
#line 1 "UserTemplate.tt"
public class User { public string Name; }
#line 10 "UserTemplate.tt"
public void Save() { } // 編譯錯誤將顯示 UserTemplate.tt 第 10 行
// 隱藏產生的樣板程式碼,偵錯時直接跳過
#line hidden
[GeneratedCode("MyGenerator", "1.0")]
public partial class GeneratedClass { ... }
#line default
// 僅在這個區塊停用 CS0168 (變數已宣告但未使用)
#pragma warning disable CS0168
int unused = 42; // 不會出現警告
#pragma warning restore CS0168
// 專案層級:.csproj 設定
CS0168;CS0219
#region 建構子、#region 公開方法、#region 介面實作。#region Generated Code。C# 預處理器指令雖不如 C/C++ 強大,但條件編譯、診斷控制、行號映射、程式碼組織等功能在實務開發中不可或缺。掌握 #if/#define 條件編譯、#warning/#error 靜態檢查、#line 產生器支援、#pragma warning 精準控制,能讓建置流程更彈性、偵錯更精準、原始碼更易維護。