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

我有这样一段代码:

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

如果我发布版本,编译器是否优化了这一点? 还是评估停留,从而花费一些处理时间?

是的,至less在Debug调用时是这样。 如果JIT编译器也删除了对if的评估,我不能在这里看到,但是我猜这是因为方程没有任何副作用。

但是,通过调用Debug.WriteLineIf (不依赖于JIT编译器)来移除评估,您最好保持安全。

为了完整性,编译器删除Debug.WriteLine的certificate。


发布版本中的代码:

 .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 

debugging版本中的代码:

 .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 

正如你所看到的,Release模式没有调用Debug.WriteLine ,Debug模式的作用。

从Debug类的MSDN页面:

如果您使用Debug类中的方法来打印debugging信息并使用声明来检查逻辑,则可以使代码更健壮,而不会影响运输产品的性能和代码大小。

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

如您所见,编译器将省略对非debugging版本上Debug成员的任何调用。 但是,它不会阻止程序检查您的if语句。 如果您希望编译器也忽略if语句,则可以使用预处理器指令来封装整个块,如下所示:

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

语言规范要求C#编译器除去Debug调用对其参数的评估。

如果.NET JIT是一个复杂的JIT,它将确定string方法调用不是副作用,并且可以被删除。 .NET JIT不是非常复杂的,所以实际上它仍然可以调用这个方法。 让我们找出来。

在Release模式下编译程序,反编译并在4.6.2上以x64的forms运行,而不使用Debugger抑制优化。

  static void Main() { var state = GetState(); if (state != "Ok") { Debug.WriteLine(state); } } [MethodImpl(MethodImplOptions.NoInlining)] static string GetState() { return "x"; } 

C#编译器将string不等式调用保持原样:

在这里输入图像说明

在这里输入图像说明

我不确定规范是否允许优化,因为这可能是一个副作用的方法。 不知道什么编译器是可以承担的。

我们的梦幻般的JIT也没有消除电话:

在这里输入图像说明

(1)是GetState()和(2)是string.!=


使用Debug.WriteLineIf是因为:

17.4.2.1条件方法用条件属性装饰的方法是一个条件方法。 条件属性通过testing条件编译符号来指示条件。 调用条件方法可以包含或省略,具体取决于该符号是否在调用点定义。 如果定义了符号,则包含呼叫; 否则,呼叫(包括接收者的评估和呼叫参数)被省略。