当C#编译器的内容具有Conditional属性时,它是否会优化foreach块?

Gui*_*res 7 c# debugging compiler-optimization

我正在编写一些调试代码,我想知道我在做什么可能会损害性能.

我们来看看代码:

foreach (var item in aCollection)
    Debug.WriteLine(item.Name);
Run Code Online (Sandbox Code Playgroud)

我知道Debug类使用Conditional属性来避免在发布模式下编译(或者每当DEBUG未定义时),但是当在发布模式下编译时,这最终会成为徒劳/空迭代还是会被编译器优化?

pid*_*pid 7

您没有在此处利用任何编译器符号.包裹它们:

#if DEBUG

    // your code here

#endif
Run Code Online (Sandbox Code Playgroud)

这种方法的优点:

  • [Conditional]method属性大大降低了可读性.在调用方面,在编译代码中不会发生调用并不明显.团队应该避免采用这种做法,而采用更明确的条件编译方法.即便评论也是不可取的,因为大型团队中总会有人忘记评论这样的内容.相反,上面的示例很容易阅读(VS2010 +甚至在不是当前构建配置文件的一部分时对文本进行着色).
  • 构建集合可能非常昂贵(eG使用数据库中的数据构建1000个项目).在这些情况下,编译器符号允许更容易和更清晰地剔除感兴趣的代码,而不会留下空循环或集合的构造.


Mik*_*bel 3

C# 编译器不会优化枚举,因为枚举集合的行为可能会产生副作用:

  1. 对于数组,对数组进行索引的行为意味着副作用(并且 C# 编译器将foreach数组上的循环重写为索引循环)。
  2. 对于其他集合,调用GetEnumerator()MoveNext()意味着副作用。

在这两种情况下,潜在的null取消引用都是副作用。

调用[Conditional]方法时,编译后的代码中只会省略方法调用及其形式参数。请注意,即使有副作用的参数也会被省略。然而,周围的代码不会被省略。

我自己的测试表明,即使添加显式null检查也不会诱使 C# 编译器优化枚举,即使对于简单的数组也是如此。

JIT 编译器是否优化了枚举代码是另一个问题。如果它能够证明该集合始终是非的null 并且没有其他有意义的副作用,那么它可能会发生。JIT可能足够复杂,可以对数组执行此操作;不过,我不会打赌。如果您担心增加的开销,请将枚举代码放置在#if@pid 建议的区域内。