前置處理器指令

小提示

剛開始開發軟體嗎? 你不會馬上需要預處理器指令。 先專注於 入門 教學,等到專案需要條件編譯或建置設定時再回來這裡。

有其他語言的經驗嗎? 如果你熟悉 #ifdef C/C++ 或其他語言的條件編譯,C# 預處理器指令的運作方式類似。 快速略過到你需要的語法。

C# 預處理器指令告訴編譯器在建置應用程式時該包含、排除或不同處理哪些程式碼。 此指引可能會改變最終的計畫。 預處理器指令總是以#開頭,必須出現在自己的行上(忽略前置空白)。 你可以在指令後加上尾記。 雖然 語言參考 書記錄了所有可用的指令,但有三類涵蓋日常使用:

  • 檔案式應用程式 (#:)- 設定檔案式應用程式。
  • 條件編譯(#if / #elif / #else / #endif)— 根據建置配置或目標框架,包含或排除程式碼。
  • 警告抑制 (#pragma warning)— 抑制或還原特定的編譯器警告。

基於檔案的應用程式指令

從 C# 14 開始, 基於檔案的應用程式 會使用兩個額外的指令:

  • #! — 那一行能直接在 Unix 上執行檔案的 shebang 行(例如, ./Program.cs)。 這需要在檔案()上設定chmod +x <file>權限。
  • #: — 建置系統指令,用於配置套件、SDK 設定及其他單一檔案程式的選項。

使用 #:package 來新增 NuGet 套件。 例如,以下基於檔案的應用程式使用此 Spectre.Console 套件來渲染樣式輸出:

#!/usr/bin/env dotnet
#:package Spectre.Console@*

AnsiConsole.MarkupLine("[bold green]Hello[/] from a file-based app!");

你可以用 來指定精確版本 @,或用 @* 來拉取最新版本。 新增多個 #:package 指令以包含更多套件:

#:package Serilog@3.1.1

其他 #: 指令則允許你參考專案、設定 MSBuild 屬性,或更改 SDK:

#:project ../SharedLibrary/SharedLibrary.csproj
#:property PublishAot=false
#:sdk Microsoft.NET.Sdk.Web

完整指令清單請參見 檔案式應用程式 及 語言參考。

條件式編譯

使用 #if、 #elif、 #else、 , #endif 根據符號是否定義來包含或排除代碼。 最常見的符號是DEBUG(在除錯建置時自動設定)以及目標框架符號,例如:NET10_0_OR_GREATER

static void ConfigureLogging()
{
#if DEBUG
    Console.WriteLine("Debug logging enabled — verbose output active.");
#else
    Console.WriteLine("Release logging — errors only.");
#endif
}

建置系統會在你以偵錯設定進行建置時定義DEBUG符號。 你不需要自己定義它。 目標框架符號(例如NET10_0_OR_GREATER 和NET8_0_OR_GREATER)允許你撰寫能適應不同 .NET 版本的多目標專案程式碼。

你可以將符號與邏輯運算子結合: && (和)、 || (或)、 ! (非):

static void ShowPlatformInfo()
{
#if NET10_0_OR_GREATER
    Console.WriteLine("Running on .NET 10 or later.");
#elif NET8_0_OR_GREATER
    Console.WriteLine("Running on .NET 8 or 9.");
#else
    Console.WriteLine("Running on an older .NET version.");
#endif
}

在檔案頂端使用 #define 來定義你自己的符號。 你也可以在專案檔案中使用 DefineConstants 屬性來定義整個專案的符號。

警告抑制

用 #pragma warning disable 來抑制特定的編譯器警告,並 #pragma warning restore 重新啟用它們。 抑制範圍應盡可能地狹窄:

    static void ProcessData()
    {
        try
        {
            // Some operation that might fail
            var data = File.ReadAllText("config.json");
            Console.WriteLine($"Config loaded: {data.Length} characters");
        }
#pragma warning disable CS0168 // Variable is declared but never used
        catch (FileNotFoundException ex)
#pragma warning restore CS0168
        {
            // Fall back to defaults — the exception details aren't needed here
            Console.WriteLine("Config file not found, using defaults.");
        }
    }

小提示

請務必指定警告號碼,例如 CS0168,而非關閉所有警告。 這種做法能讓壓制持續有針對性,並清楚說明 為什麼 要壓制警告。