C# 预处理器指令

`#if`、`#define`、条件编译、以及 `[Conditional]` 特性。

Intermediate
Key PointsC# 的预处理器只能做条件编译,没有宏替换和文件包含。

常用的几个

C#
#define FEATURE_X          // 必须在文件最前面

#nullable enable

class Program
{
    static void Main()
    {
#if DEBUG
        Console.WriteLine("调试模式");
#else
        Console.WriteLine("发布模式");
#endif

#if FEATURE_X
        Console.WriteLine("功能 X 已启用");
#endif

#if NET8_0_OR_GREATER
        Console.WriteLine("运行在 .NET 8 或更高");
#endif
    }
}
Output
调试模式
功能 X 已启用
运行在 .NET 8 或更高
DirectiveUse
#define / #undef定义/取消符号(文件级,必须在最前)
#if / #elif / #else / #endif条件编译
#region / #endregion折叠代码块(IDE 用)
#pragma warning启用/禁用警告
#nullable可空检查开关
#error / #warning主动报错/警告
#line改行号映射(代码生成用)

项目级符号

XML
<PropertyGroup>
  <DefineConstants>$(DefineConstants);FEATURE_X;TRACE_LOG</DefineConstants>
</PropertyGroup>

DEBUG and TRACE come from the build configuration: the Debug profile defines DEBUG, Release does not. Custom symbols belong in the project file so you can switch without touching code.

平台与版本判断

C#
#if NET8_0
Console.WriteLine("正好是 .NET 8");
#endif

#if NET8_0_OR_GREATER
Console.WriteLine("NET8_0_OR_GREATER");
#endif

#if WINDOWS
Console.WriteLine("Windows 目标");
#elif LINUX
Console.WriteLine("Linux 目标");
#endif

// 运行时判断(不是预处理器)
if (OperatingSystem.IsWindows())
{
    Console.WriteLine("运行在 Windows");
}
Output
正好是 .NET 8
NET8_0_OR_GREATER
Windows 目标
运行在 Windows
Compile-time symbols and runtime checks differ. #if WINDOWS decides whether code is compiled in; OperatingSystem.IsWindows() decides which branch runs. Only the latter handles cross-platform execution.

[Conditional] 特性

C#
using System.Diagnostics;

class Log
{
    [Conditional("DEBUG")]
    public static void Debug(string msg) => Console.WriteLine($"[DEBUG] {msg}");

    public static void Info(string msg) => Console.WriteLine($"[INFO] {msg}");
}

Log.Debug("只在 Debug 配置下输出");
Log.Info("总是输出");
Output
[DEBUG] 只在 Debug 配置下输出
[INFO] 总是输出

[Conditional] beats #if because the call site needs no directives: in Release the whole call is removed, arguments included. Ideal for logging and assertions.

该不该用

  • 该用 —— 平台差异(#if WINDOWS)、框架版本兼容、调试日志
  • 慎用 —— 大量 #if 会让代码难以阅读,两条分支可能只测了一条
  • 改用 —— 业务开关放配置中心,别用编译期符号
The danger of #if branches is uneven test coverage: CI may only build Debug, leaving Release-only compile errors unnoticed. Build both in CI.

Friends & Partners