ConditionalAttribute是否应该删除整行,或者只是方法调用?

Dan*_*Tao 7 .net debugging conditional release

根据ConditionalAttribute班上的文件:

将ConditionalAttribute应用于方法指示编译器不应将对该方法的调用编译为Microsoft中间语言(MSIL),除非定义了与ConditionalAttribute关联的条件编译符号.

对我来说,这就是说该Conditional属性只改变单个方法调用级别的行为.但请考虑以下代码段:

class InstanceType
{
    public InstanceType DoSideEffects()
    {
        Console.WriteLine("Side effects!");
        return this;
    }

    public InstanceType DoMoreSideEffects()
    {
        Console.WriteLine("More side effects!");
        return this;
    }

    [Conditional("DEBUG")]
    public void ConditionalMethod()
    {
        Console.WriteLine("Conditional method run.");
    }
}

class Program
{
    static void Main()
    {
        var x = new InstanceType();

        // The compiler appears to strip out this entire line
        // in a Release build.
        x.DoSideEffects().DoMoreSideEffects().ConditionalMethod();

        var y = new InstanceType();

        // When each method call appears on its own line,
        // the first two methods are included as expected.
        y.DoSideEffects();
        y.DoMoreSideEffects();
        y.ConditionalMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

比较Debug和Release版本的输出:

DEBUG                    RELEASE
Side effects!            Side effects!
More side effects!       More side effects!
Conditional method run.
Side effects!
More side effects!
Conditional method run.

是否在某处指定了此行为?我原以为两个版本都应该具有相同的输出,除了读取"条件方法运行"的行.

Maa*_*ate 2

有趣的功能:-)我从来没有注意到这一点。

我看了IL。我相信,这并不能解释行为(编译过程),但它无论如何都记录了结果。

IL 中明显省略了整个 C# 代码行:

  • 在 DEBUG 编译中,创建一个新对象(x 变量),存储在位置 0 并加载。之后依次应用三个方法:DoSideEffects()、DeMoreSideEffects() 和 ConditionalMethod()
  • 在 RELEASE 编译中,仍然会创建变量,但由于不需要它,因此会立即弹出。相反,y 变量存储在位置 0 并加载。

对我来说,这看起来真的像一个错误。似乎可以在 IL 中排除 ConditionalMethod() 调用。但看来你是对的,整条线都被遗漏了。

// DEBUG compilation
.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       58 (0x3a)
  .maxstack  1
  .locals init (class ConsoleApplication3.InstanceType V_0,
           class ConsoleApplication3.InstanceType V_1)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication3.InstanceType::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects()
  IL_000d:  callvirt   instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects()
  IL_0012:  callvirt   instance void ConsoleApplication3.InstanceType::ConditionalMethod()
  IL_0017:  nop
  IL_0018:  newobj     instance void ConsoleApplication3.InstanceType::.ctor()
  IL_001d:  stloc.1
  IL_001e:  ldloc.1
  IL_001f:  callvirt   instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects()
  IL_0024:  pop
  IL_0025:  ldloc.1
  IL_0026:  callvirt   instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects()
  IL_002b:  pop
  IL_002c:  ldloc.1
  IL_002d:  callvirt   instance void ConsoleApplication3.InstanceType::ConditionalMethod()
  IL_0032:  nop
  IL_0033:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_0038:  pop
  IL_0039:  ret
} // end of method Program::Main

// RELEASE compilation
.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       33 (0x21)
  .maxstack  1
  .locals init ([0] class ConsoleApplication3.InstanceType y)
  IL_0000:  newobj     instance void ConsoleApplication3.InstanceType::.ctor()
  IL_0005:  pop
  IL_0006:  newobj     instance void ConsoleApplication3.InstanceType::.ctor()
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects()
  IL_0012:  pop
  IL_0013:  ldloc.0
  IL_0014:  callvirt   instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects()
  IL_0019:  pop
  IL_001a:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_001f:  pop
  IL_0020:  ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)