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

时间:2014-02-03 15:25:06

标签: c# debugging compiler-optimization

我正在编写一些调试代码,我想知道我在做什么可能会影响性能。

让我们来看看代码:

foreach (var item in aCollection)
    Debug.WriteLine(item.Name);

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

3 个答案:

答案 0 :(得分:7)

您没有在此处利用任何编译器符号。将它包装在这些内容中:

#if DEBUG

    // your code here

#endif

这种方法的优点:

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

答案 1 :(得分:4)

那个foreach不会被抹去。

编译后的代码如下:

foreach (var item in aCollection)
{
   ;
}

无论如何都会列举该集合。

答案 2 :(得分:3)

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

  1. 对于数组,索引到数组中的行为意味着副作用(并且C#编译器将数组上的foreach循环重写为索引循环)。
  2. 对于其他馆藏,对GetEnumerator()MoveNext()的调用意味着副作用。
  3. 在这两种情况下,潜在的null取消引用都是副作用。

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

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

    JIT编译器是否优化了枚举代码是另一个问题。它可能,如果它可以证明该集合总是非null ,则没有其他有意义的副作用。 JIT 可能足够复杂,可以为数组做到这一点;不过,我不会赌它。如果增加的开销涉及到您,请将枚举代码放在#if区域中,如@pid所示。