IL 代码中的 C# 预处理器指令

C# Preprocessor Directives in the IL code

我尝试在 C# 中使用简单的预处理器指令进行调试和发布模式。

例如:

using System;
public class C {
    public void M() {
        #if DEBUG
            Console.WriteLine("Debug");
        #else
            Console.WriteLine("Release");
        #endif
    }
}

这段代码非常简单明了。

但是当我查看 IL 代码时,我对调试指令一无所知。

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit C
    extends [mscorlib]System.Object
{
    // Methods
    .method public hidebysig 
        instance void M () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 13 (0xd)
        .maxstack 8

        IL_0000: nop
        IL_0001: ldstr "Release"
        IL_0006: call void [mscorlib]System.Console::WriteLine(string)
        IL_000b: nop
        IL_000c: ret
    } // end of method C::M

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x205e
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: nop
        IL_0007: ret
    } // end of method C::.ctor

} // end of class C

我很感兴趣,为什么会这样。

我的意思是为什么我在 IL 代码中看不到有关 DEBUG 模式的任何信息?

P.S。我使用 sharplab 查看 IL 代码。

P.S.2直播example

这是因为预处理器指令被编译器用来根据配置生成不同的IL代码。 CLR 不使用它。

至于为什么 SharpLab 没有做正确的事情,它使用 Rosyln 并且只设置了优化设置。它不设置预处理器变量。

public void SetOptimize([NotNull] IWorkSession session, [NotNull] string optimize) {
    var project = session.Roslyn.Project;
    var options = ((CSharpCompilationOptions)project.CompilationOptions);
    session.Roslyn.Project = project.WithCompilationOptions(
        options.WithOptimizationLevel(optimize == Optimize.Debug ? OptimizationLevel.Debug : OptimizationLevel.Release)
    );
}

我建议您向 SharpLab 提出一个问题,他们实施此功能以按预期工作。

有两个概念似乎让您感到困惑。

  1. Release/Debug编译模式:

    这控制编译器是否将调试信息发送到代码中(例如 NOP 用于设置断点的指令)以及一些其他方面,例如在编译器和 JIT 级别执行的优化。这是基于 C# 编译器的 /debug 参数。

  2. 预处理器符号:

    这控制了为编译定义了哪些符号运行。默认情况下,当使用 Visual Studio 创建 C# 项目时,这些在调试模式下设置为 DEBUGTRACE,在发布模式下设置为 TRACE。这些符号然后用于解析您正在使用的 #if 指令。这是基于 C# 编译器的 /define 参数

你的情况似乎是你的工具告诉 C# 编译器在 Debug/Release 模式下 运行 但不提供预期的预处理器符号 (DEBUG)在参数中。因此,您会在 Release 和 Debug 配置中看到非 DEBUG 代码。

另请参阅:Microsoft docs: C# compiler options by category