Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#编译器是否删除封装debug.writeline的if_C#_.net_Compiler Optimization - Fatal编程技术网

C#编译器是否删除封装debug.writeline的if

C#编译器是否删除封装debug.writeline的if,c#,.net,compiler-optimization,C#,.net,Compiler Optimization,我有一段代码如下: if (state != "Ok") { Debug.WriteLine($"Error occured: {state}, {moreInfo}"); } 如果我进行发布构建,编译器是否会对此进行优化?或者评估是否会保留下来并因此花费一些处理时间?是的,它会保留下来,至少对于Debug调用是这样的。我在这里看不到JIT编译器是否也删除了对if的求值,但我想是的,因为这个等式没有任何副作用 但是,通过调用Debug.WriteLineIf,可以更好地保护它的安全性

我有一段代码如下:

if (state != "Ok")
{
     Debug.WriteLine($"Error occured: {state}, {moreInfo}");
}

如果我进行发布构建,编译器是否会对此进行优化?或者评估是否会保留下来并因此花费一些处理时间?

是的,它会保留下来,至少对于
Debug
调用是这样的。我在这里看不到JIT编译器是否也删除了对
if
的求值,但我想是的,因为这个等式没有任何副作用

但是,通过调用
Debug.WriteLineIf
,可以更好地保护它的安全性,因为它不依赖于JIT编译器来删除计算

为了完整性,编译器删除
Debug.WriteLine
的证明


发布版本中的代码:

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       17 (0x11)
  .maxstack  8
  IL_0000:  call       string [mscorlib]System.Console::ReadLine()
  IL_0005:  ldstr      "Ok"
  IL_000a:  call       bool [mscorlib]System.String::op_Inequality(string,
                                                                   string)
  IL_000f:  pop
  IL_0010:  ret
} // end of method Program::Main
调试生成中的代码:

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       42 (0x2a)
  .maxstack  2
  .locals init ([0] string state,
           [1] bool V_1)
  IL_0000:  nop
  IL_0001:  call       string [mscorlib]System.Console::ReadLine()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldstr      "Ok"
  IL_000d:  call       bool [mscorlib]System.String::op_Inequality(string,
                                                                   string)
  IL_0012:  stloc.1
  IL_0013:  ldloc.1
  IL_0014:  brfalse.s  IL_0029
  IL_0016:  nop
  IL_0017:  ldstr      "Error occured: {0}"
  IL_001c:  ldloc.0
  IL_001d:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0022:  call       void [System]System.Diagnostics.Debug::WriteLine(string)
  IL_0027:  nop
  IL_0028:  nop
  IL_0029:  ret
} // end of method Program::Main
正如您所看到的,发布模式没有调用调试.WriteLine,而调试模式是这样做的。

来自

如果使用
Debug
类中的方法打印调试信息并使用断言检查逻辑,则可以使代码更加健壮,而不会影响产品的性能和代码大小

ConditionalAttribute
属性应用于
Debug
的方法。支持
ConditionalAttribute
的编译器忽略对这些方法的调用,除非将“DEBUG”定义为条件编译符号

如您所见,编译器将忽略对非调试版本上的
Debug
成员的任何调用。但是,它不会阻止程序检查if语句。如果希望编译器也忽略If语句,可以使用a将整个块括起来,如下所示:

#if DEBUG
if (state != "Ok")
{
    Debug.WriteLine($"Error occured: {state}, {moreInfo}");
}
#endif
语言规范要求C#编译器删除
Debug
调用及其参数的计算

如果.NET JIT是一个复杂的JIT,它将确定string方法调用不会产生副作用,并且可以删除。NET JIT不是很复杂,所以实际上它仍然有可能调用该方法。让我们看看

在发布模式下编译程序,反编译并在4.6.2上以x64的形式运行,而无需调试器抑制优化

    static void Main()
    {
        var state = GetState();
        if (state != "Ok")
        {
            Debug.WriteLine(state);
        }
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static string GetState()
    {
        return "x";
    }
C#编译器保留了字符串不等式调用的完整性:

我不确定规范是否允许对此进行优化,因为这可能是一种副作用的方法。不确定允许编译器对其进行什么假设

我们出色的JIT也没有取消呼叫:

(1) 是
GetState()
,(2)是
字符串=


使用Debug.WriteLineIf
是因为:

17.4.2.1条件法 用条件属性修饰的方法是条件方法。Conditional属性通过测试条件编译符号来指示条件。对条件方法的调用被包括或省略,这取决于此符号是否在调用点定义。如果定义了符号,则包括呼叫;否则,省略呼叫(包括对接收器和呼叫参数的评估)


使用
Debug.WriteLineIf
方法。注意:没有单一的C#编译器。有几种C#编译器,每种都有许多版本。C#规范几乎没有(如果有的话)强制性的优化,因此您的答案可能只针对特定的编译器和特定的版本。据我所知,不是这样。这是一个黑盒子。我不知道Debug.WriteLineIf。我喜欢!谢谢那么,JIT删除您所要求的if的证据在哪里呢?JIT确实是一个黑盒子,它没有提供任何明确的/文档化的保证来删除if语句,但是您当然可以根据经验验证它是否会删除if语句。在调试器下运行编译后的代码并查看反汇编。确保在调试器下运行时启用JIT优化;我不记得它在VS中是否默认关闭。发布代码仍然调用
System.String::op_
。我想说它仍然计算
if
语句,但它被视为有一个空的主体。你能参考一下它在规范中指出的
Debug.X
调用必须删除的地方吗?@Jeroenvanevel我补充道。