小窍门
开发软件的新手? 无需立即使用预处理器指令。 请首先关注 入门 教程,并在项目需要条件编译或生成配置时返回此处。
是否在其他语言中有经验? 如果你熟悉 #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,而不是禁用所有警告。 此方法将保持抑制目标,并明确 为什么 禁止显示警告。