19

If I have a for loop like the following:

foreach(string email in installerEmails.Split(','))
{
    Console.WriteLine(email);
}

Will the Split() call be made on each iteration of the loop? Do I need to store it in a temp array before iterating through it?

FrankTheBoss
  • 193
  • 1
  • 4
  • 1
    possible duplicate of [How does foreach work when looping through function results?](http://stackoverflow.com/questions/1632810/how-does-foreach-work-when-looping-through-function-results) – Adam Lear Oct 14 '10 at 14:51

6 Answers6

27

No. It will iterate on the result of that call, i.e., the return type of Split which is a string array: string[].

Ahmad Mageed
  • 94,561
  • 19
  • 163
  • 174
5

The result of Split is evaluated once, then GetEnumerator() is called on it. This returns an IEnumerator on which the MoveNext method and Current property is called in each iteration.

It's basically equivalent to:

string[] enumerable=installerEmails.Split(',');
IEnumerator<string> enumerator=enumerable.GetEnumerator();
while(enumerator.MoveNext())
{
    string email=(string)enumerator.Current;
    Console.WriteLine(email);
}

One ugly detail is the explicit cast to the type you give in the for loop the compiler generates. This was useful in C# 1.0 where IEnumerator wasn't generic.

I forgot that the Enumerator gets disposed. See Jon Hanna's answer for the code which includes dispose.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
4

No. Just debug your code. you'll see the Split() method is only called once.

Kamyar
  • 18,639
  • 9
  • 97
  • 171
3

No. The object returned by Split (which happens to be an array, but the same applies to other enumerable objects) is what defines the loop after all. If it has zero or a million items, it is it that is defining the zero or million iterations, which it couldn't do if it kept being called.

For a bit more detail, the code produced becomes equivalent to:

string[] temp = installerEmails.Split(',');
var enumerator = temp.GetEnumerator();
try
{
  while(enumerator.MoveNext())
  {
    string email = (string)enumerator.Current;
    Console.WriteLine(email);
  }
}
finally
{
  if(enumerator is IDisposable)
    ((IDisposable)enumerator).Dispose()
}

As you can see, .Split() is called only once.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
1

The Split will be called once, which results in an array. The foreach then uses a single enumerator to iterate over the array.

Niels van der Rest
  • 31,664
  • 16
  • 80
  • 86
  • 4
    Optimise it from what? It's what is defining the loop in the first place. – Jon Hanna Oct 14 '10 at 14:43
  • @Jon Hanna: My mistake, I was thinking in the context of a while loop for a second. It wouldn't optimize anything there, that would defeat the purpose of `while` :) I've removed it from my answer, thanks. – Niels van der Rest Oct 14 '10 at 14:50
0

No. .Split() returns an IEnumerable, and that will be used to iterate over.

Rik
  • 28,507
  • 14
  • 48
  • 67