Does the C# compiler optimize foreach blocks when its contents have the Conditional attribute?

StackOverflow https://stackoverflow.com/questions/21531131

Domanda

I'm writing some debug code at work, and I'm wondering if what I'm doing might hurt performance or not.

Let's get to the code:

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

I know that the Debug class uses the Conditional attribute to avoid compilation in release mode (or whenever DEBUG is undefined), but would this end up as a futile/empty iteration when compiled in release mode or would it be optimized by the compiler?

È stato utile?

Soluzione 3

The C# compiler will not optimize away the enumeration because the act of enumerating over a collection may produce side effects:

  1. In the case of an array, the act of indexing into the array implies a side effect (and the C# compiler rewrites foreach loops over arrays into indexing loops).
  2. For other collections, the calls to GetEnumerator() and MoveNext() imply side effects.

In both cases, the potential null dereference is a side effect.

When invoking a [Conditional] method, only the method call and its formal arguments will be omitted from the compiled code. Note that even arguments with side effects would be omitted. However, no surrounding code would be omitted.

My own tests show that even adding an explicit null check will not coax the C# compiler into optimizing away the enumeration, even for a simple array.

Whether the JIT compiler optimizes away the enumeration code is another question. It might, if it can prove that the collection is always non-null and that there are no other meaningful side effects. The JIT might be sophisticated enough to do this for arrays; I wouldn't bet on it, though. If the added overhead concerns you, place the enumeration code within an #if region as @pid suggests.

Altri suggerimenti

You are not leveraging any compiler symbols here. Wrap it inside these:

#if DEBUG

    // your code here

#endif

Advantages of this approach:

  • readability is greatly decreased by the [Conditional] method attribute. It is not obvious on the invoking side that an invocation will not take place in the compiled code. Teams should refrain from that practice in favor of more explicit conditional compilation methods. Even commenting is not advisable because there's always that someone in large teams who forgets to comment stuff like this. The example above, instead, is easy to read (VS2010+ even shades the text when it is not part of the current build profile).
  • constructing collections might be very expensive (e.G. constructing 1000 items with data from a database). In those cases compiler symbols allow for easier and cleaner culling of the interested code, without leaving an empty loop or the construction of the collection.

That foreach will not be wiped away.

The compiled code will be something like:

foreach (var item in aCollection)
{
   ;
}

the collection will be enumerated anyway.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top