Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# loops: iterating through an array

Tags:

c#

loops

If I have a loop such as below:

foreach (string pass in new string[] { "pass1", "pass2", "pass3" })
{
 x = pass; //etc
}

does the anonymous string array get created once initially, or recreated once for each pass?

I believe the former, but collegues are convinced this is a bug waiting to happen because they say every iteration of the foreach loop results in a new string array being created.

The VS Disassembly code suggests I am right, but I want to be sure.

The reason we are looking at this is to try to understand a mysterious bug that reports that a collection has been changed whilst iterating over it.

like image 920
haughtonomous Avatar asked Feb 27 '13 14:02

haughtonomous


2 Answers

According to Eric Lippert blog and specification, foreach loop is a syntactic sugar for:

{
  IEnumerator<string> e = ((IEnumerable<string>)new string[] { "pass1", "pass2", "pass3" }).GetEnumerator();
   try
   { 
     string pass; // OUTSIDE THE ACTUAL LOOP
      while(e.MoveNext())
      {
        pass = (string)e.Current;
        x = pass;
      }
   }
   finally
   { 
      if (e != null) ((IDisposable)e).Dispose();
   }
}

As you can see, enumerator is created before loop.

@Rawling correctly pointed, that array treated a little different by compiler. Foreach loop is optimized into for loop with arrays. According to The Internals of C# foreach your code for C# 5 will look like:

string[] tempArray;
string[] array = new string[] { "pass1", "pass2", "pass3" };
tempArray = array;

for (string counter = 0; counter < tempArray.Length; counter++)
{
    string pass = tempArray[counter];
    x = pass;
}

Initialization also happens only once.

like image 82
Sergey Berezovskiy Avatar answered Sep 30 '22 17:09

Sergey Berezovskiy


If you look in ILSpy, this code is translated into something like

string[] array = new string[]
{
    "pass1",
    "pass2",
    "pass3"
};
for (int i = 0; i < array.Length; i++)
{
    string pass = array[i];
}

so yes, the array is only created once.

However, the best reference to convince your colleagues is probably section 8.8.4 of the C# specification, which will tell you essentially what LazyBerezovsky's answer does.

like image 27
Rawling Avatar answered Sep 30 '22 19:09

Rawling