【问题标题】:Will conditionals that are always false be removed by compiler in C#C# 中的编译器是否会删除始终为假的条件
【发布时间】:2009-01-14 16:15:21
【问题描述】:

假设我在 c# 中有以下代码 sn-p

static const bool DO_PERFORMANCE_CODE = false;

if (DO_PERFORMANCE_CODE)
{
   // performance monitoring code goes here
}

编译器会删除该代码吗?这是我想要的功能。基本上我想模仿 C# 中的条件编译的东西,但我想要除 Release 和 Debug 之外的更多配置。如果有更好的方法,我愿意听取。

【问题讨论】:

    标签: c# .net performance


    【解决方案1】:

    当您构建“调试”时,定义了预处理器变量 DEBUG。所以,你可以这样做:

    public void MyFunc()
    {
    //do release stuff
    #if DEBUG
    //do performance testing
    #endif
    //finish release stuff
    }
    

    当你切换到发布模式时,编译器会忽略它。

    或者,如果您不想在调试模式下进行测试,您可以定义自己的预处理器变量,确保在想要测试时使用“#define PERFORMANCE_TESTING”,在不想测试时将其注释掉。

    #define PERFORMANCE_TESTING
    
        public void MyFunc()
        {
        //do release stuff
        #if PERFORMANCE_TESTING
        //do performance testing
        #endif
        //finish release stuff
        }
    

    【讨论】:

    • 当我看到你的回答时,我以为你只有#if DEBUG 部分。我会给你一个赞成票,因为他说他想要的不仅仅是调试和发布。
    • 老实说,我做到了。然后我意识到,如果您专注于性能,您可能希望在发布模式下进行测试。
    • 是否可以嵌套#ifs?我会这么认为,但我不确定。
    • 是的,您可以嵌套多个预处理器指令。
    • 而且很难很快跟上
    【解决方案2】:

    定义自己的符号可能更简洁,但我很好奇编译器会做什么,所以我做了一些实验(在发布模式下使用 VS 2008)。

    有了这个:

    class Program
    {
        static void Main(string[] args)
        {
            bool foo = false;
    
            if (foo)
            {
                Console.WriteLine("Hello, world?");
            }
        }
    }
    

    编译器仍然为 if 语句生成代码:

    .method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      // Code size       16 (0x10)
      .maxstack  1
      .locals init ([0] bool foo)
      IL_0000:  ldc.i4.0
      IL_0001:  stloc.0
      IL_0002:  ldloc.0
      IL_0003:  brfalse.s  IL_000f
      IL_0005:  ldstr      "Hello, world\?"
      IL_000a:  call       void [mscorlib]System.Console::WriteLine(string)
      IL_000f:  ret
    } // end of method Program::Main
    

    如果你这样做:

    class Program
    {
        static void Main(string[] args)
        {
            bool foo = false;
    
            if (false)
            {
                Console.WriteLine("Hello, world?");
            }
        }
    }
    

    它不会为 if 语句生成代码:

    .method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      // Code size       1 (0x1)
      .maxstack  8
      IL_0000:  ret
    } // end of method Program::Main
    

    它似乎也跳过了分配了一个从未使用过的值的变量。

    我检查了 ildasm.exe,Visual Studio 附带的反汇编程序。

    【讨论】:

      【解决方案3】:

      我使用 Reflector 和 Visual Studio 2008 SP1 进行了一系列测试,这就是我发现的。

      1. 在错误的条件编译 (#if SOMETHING_FALSE...) 中,代码不仅没有被编译,而且编译器甚至不会报错
      2. 在基于常量(即 if(false) { ... 或 if(constant_declared_false) { ...) 变量声明的值和引用类型的始终为假条件内的代码块中编译,但没有编译可执行代码(方法调用、for 循环、设置变量的值等)。
      3. 如果我将一个局部变量设置为 false 并测试该局部变量,所有代码都会被编译。

      【讨论】:

        【解决方案4】:

        您可以定义自己的预编译器变量。

         #define temp
        
         #if temp
         // Do something
         #endif
        

        【讨论】:

          【解决方案5】:

          您可以在文件顶部定义自己的常量:

           #define SUPERDOOPERDEBUG
          
           using System;
          
           ....
          
          
           #if SUPERDOOPERDEBUG
          
               // something
          
           #endif
          

          此外,您可以设置不同的构建配置,而不仅仅是“发布”和“调试”(请参阅​​构建 -> 配置菜单或在项目 -> 属性菜单中定义其他条件编译符号

          【讨论】:

          • 哇,我比你快 14 秒。
          • 小工具督察,下次我会找你的!
          【解决方案6】:

          您可以定义除 DEBUG/RELEASE 之外的更多符号...只需查看项目属性 :-) 然后您可以使用预处理器指令语法根据项目配置选择性地包含内容

          【讨论】:

            【解决方案7】:

            您不仅限于 DEBUG 和 RELEASE。您可以使用#define 或在项目属性中指定其他常量。

            【讨论】:

            • 哈。 #5具有相同的答案。抱歉打扰了。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-12-21
            • 1970-01-01
            • 2015-04-23
            • 2017-04-29
            • 1970-01-01
            相关资源
            最近更新 更多