Partilhar via


You need to be careful about how you use count in for-loops

Negotiating

Lets consider the following code

  MyCollection myCol = new MyCollection();
 myCol.AddRange(new int[] { 1, 2, 3, 4, 5, });
 for (int i = 0; i < myCol.Count; ++i)
 {
     Console.WriteLine("{0}", i);
 }

What most people forgets to consider is the condition check that happens for the for loop (in Red). In this case it is actually a call to a method get_Count. The compiler doesn't optimize this away (even when inlined)!! Since the condition is evaluated after each iteration, there's actually a method call happening each time. For most .NET code it is low-cost because ultimately it's just a small method with count being returned from an instance variable (if inlined the method call overhead also goes away). Something like this is typically written for count.

 public int Count
{
    get
    {  
        return this.count;
    }
}

Someone wrote something very similar in C, where in the for-loop he used strlen. Which means that the following code actually is O(n2) because each time you are re-calculating the length...

 for(int i = 0; i < strlen(str); ++i) {...}

Why the compiler cannot optimize it is another question. For one it's a method call and it is difficult to predict whether there's going to be any side-effect. So optimizing the call away can have other disastrous effect.

So store the count and re-use it if you know that the count is not going to change...

Comments

  • Anonymous
    May 17, 2008
    The comment has been removed

  • Anonymous
    May 17, 2008
    Ultimately this comes down to C# using C's syntax instead of having a true upper bound for loops. Consider the VB version: For i = 0 To myCol.Count - 1 Console.WriteLine(i) Next VB will never call myCol.Count more than once, so this kind of performance bug isn't possible.

  • Anonymous
    May 19, 2008
    abhinaba, thanks again for sharing your insights...sometimes you forget about the simplest things! take care - jp