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条件编译符号来指示条件。 调用条件方法可以包含或省略,具体取决于该符号是否在调用点定义。 如果定义了符号,则包含呼叫; 否则,呼叫(包括接收者的评估和呼叫参数)被省略。