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 提出一个问题,他们实施此功能以按预期工作。
有两个概念似乎让您感到困惑。
Release/Debug编译模式:
这控制编译器是否将调试信息发送到代码中(例如 NOP
用于设置断点的指令)以及一些其他方面,例如在编译器和 JIT 级别执行的优化。这是基于 C# 编译器的 /debug
参数。
预处理器符号:
这控制了为编译定义了哪些符号运行。默认情况下,当使用 Visual Studio 创建 C# 项目时,这些在调试模式下设置为 DEBUG
和 TRACE
,在发布模式下设置为 TRACE
。这些符号然后用于解析您正在使用的 #if
指令。这是基于 C# 编译器的 /define
参数
你的情况似乎是你的工具告诉 C# 编译器在 Debug/Release 模式下 运行 但不提供预期的预处理器符号 (DEBUG
)在参数中。因此,您会在 Release 和 Debug 配置中看到非 DEBUG
代码。
我尝试在 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 提出一个问题,他们实施此功能以按预期工作。
有两个概念似乎让您感到困惑。
Release/Debug编译模式:
这控制编译器是否将调试信息发送到代码中(例如
NOP
用于设置断点的指令)以及一些其他方面,例如在编译器和 JIT 级别执行的优化。这是基于 C# 编译器的/debug
参数。预处理器符号:
这控制了为编译定义了哪些符号运行。默认情况下,当使用 Visual Studio 创建 C# 项目时,这些在调试模式下设置为
DEBUG
和TRACE
,在发布模式下设置为TRACE
。这些符号然后用于解析您正在使用的#if
指令。这是基于 C# 编译器的/define
参数
你的情况似乎是你的工具告诉 C# 编译器在 Debug/Release 模式下 运行 但不提供预期的预处理器符号 (DEBUG
)在参数中。因此,您会在 Release 和 Debug 配置中看到非 DEBUG
代码。