这是由编译器控制的。所有方法都带有[Conditional]
仍将包含在 MSIL 中,但将包含.custom instance
详细说明的行[Conditional]
。在方法调用者的编译时,编译器进行词法分析,然后进行语义分析和重载解析,并找到.custom instance
IL 在您放置的方法中[Conditional]
在。因此它不会编译该调用。
所以:编译器编译了目标方法,但是不编译任何调用到那个方法。注意:该方法仍然存在,您仍然可以通过反射调用它。看the spec https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#conditional-methods
对条件方法的调用可以包含也可以省略,具体取决于调用时是否定义了该符号。如果定义了符号,则包含调用;否则,调用(包括接收者的评估和调用的参数)被省略。
你如何验证它?启动开发者命令提示符,输入ildasm <enter>
并打开相关的dll/exe。查看主叫方和被叫方[Conditional]
方法。你会看到被调用的方法有额外的 IL.custom instance
,并且在您期望的地方省略了调用方行。使用下面的代码在控制台应用程序上尝试一下。
为什么?在某些情况下,它使条件调用比使用更简单#if
. See Eric Lippert:条件编译和条件属性有什么区别? http://ericlippert.com/2009/09/10/whats-the-difference-between-conditional-compilation-and-the-conditional-attribute/
class Program
{
static void Main(string[] args)
{
AlwaysEmit();
DebugEmit();
VerboseEmit();
}
public static void AlwaysEmit()
{
Console.WriteLine("Beam me up");
}
[Conditional("DEBUG")]
public static void DebugEmit()
{
Console.WriteLine("Kirk out");
}
[Conditional("VERBOSE")]
public static void VerboseEmit()
{
Console.WriteLine("Say that again?");
}
}
而在相应的MSIL中,VerboseEmit
包含在内,但未调用自Main
:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 14 (0xe)
.maxstack 8
IL_0000: nop
IL_0001: call void RateScope.SdrApi.UploaderConsoleApp.Program::AlwaysEmit()
IL_0006: nop
IL_0007: call void RateScope.SdrApi.UploaderConsoleApp.Program::DebugEmit()
IL_000c: nop
IL_000d: ret
} // end of method Program::Main
...
.method public hidebysig static void VerboseEmit() cil managed
{
.custom instance void [mscorlib]System.Diagnostics.ConditionalAttribute::.ctor(string)
= ( 01 00 07 56 45 52 42 4F 53 45 00 00 ) // ...VERBOSE..
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Say that again\?"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Program::VerboseEmit
奖励积分。查看控制台输出和 MSIL(相应地修改 Emit 方法):
static void Main(string[] args)
{
int callCount = 0;
AlwaysEmit(++callCount);
VerboseEmit(++callCount);
DebugEmit(++callCount);
Console.WriteLine("Call count = " + callCount);
Console.ReadLine();
}