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

时间:2017-08-15 11:42:41

标签: c# .net .net-core .net-assembly

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

例如:

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

这段代码非常简单明了。

但是当我看到IL代码时,我没有关于debug指令的任何内容。

.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 live example

2 个答案:

答案 0 :(得分:6)

这是因为编译器使用预处理程序指令根据配置生成不同的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 :(得分:2)

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

  1. 发布/调试编译模式:

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

  2. 预处理程序符号:

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

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

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