.net - ConditionalAttribute 应该去掉整行,还是只去掉方法调用?

标签 .net debugging conditional release

根据 ConditionalAttribute 上的文档类(class):

Applying ConditionalAttribute to a method indicates to compilers that a call to the method should not be compiled into Microsoft intermediate language (MSIL) unless the conditional compilation symbol that is associated with ConditionalAttribute is defined.



对我来说,这就是 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();
    }
}

比较 Debug 和 Release 版本的输出:

调试发布
副作用!副作用!
副作用更大!副作用更大!
条件方法运行。
副作用!
副作用更大!
条件方法运行。

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

最佳答案

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

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

整个 C# 代码行在 IL 中显然被遗漏了:

  • 在DEBUG编译一个新对象
    创建(x 变量),存储
    在位置 0 并加载。然后
    三种方法都适用
    依次:DoSideEffects(),
    DeMoreSideEffects() 和
    条件方法()
  • 在 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
    

    关于.net - ConditionalAttribute 应该去掉整行,还是只去掉方法调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3809129/

    相关文章:

    bash - 在 tox 中运行条件 bash 命令

    asp.net - VB.NET 2.0 : Where does a URL in code come from?

    c# - 如何: Create a Key In the Registry (Visual C#)?

    Android Studio 模拟器错误 - 以非零退出值 2 结束

    python - IPython (Jupyter) 笔记本中的交互式调试

    r - if 表达式的简单求和

    regex - 通过正则表达式在 Notepad++ 中替换时如何使用条件

    .net - 类似于 VS 2010 Ultimate 的依赖关系图?

    c# - 设计n层应用程序时的困惑

    C++ 循环 : how to get program to repeat "error" message more than once anytime user enters invalid input