tags:

views:

245

answers:

3

Suppose I have the following code:

foreach(string str in someObj.GetMyStrings())
{
    // do some stuff
}

Will someObj.GetMyStrings() be called on every iteration of the loop? Would it be better to do the following instead:

List<string> myStrings = someObj.GetMyStrings();
foreach(string str in myStrings)
{
    // do some stuff
}

?

+16  A: 

No.. the function will get called once to get the IEnumerable.. and then there will be repeated call to MoveNext and Current.

Nestor
+2  A: 

GetMyStrings() retuns an object of type IEnumerable. The runtime knows how to deal with that. It calls IEnumerable.GetEnumerator() and then on that enumerator object calls MoveNext() and Current.

Matthew
+8  A: 

The function's only called once, to return an IEnumerator<T>; after that, the MoveNext() method and the Current property are used to iterate through the results:

foreach (Foo f in GetFoos())
{
    // Do stuff
}

is somewhat equivalent to:

using (IEnumerator<Foo> iterator = GetFoos().GetEnumerator())
{
    while (iterator.MoveNext())
    {
        Foo f = iterator.Current;
        // Do stuff
    }
}

Note that the iterator is disposed at the end - this is particularly important for disposing resources from iterator blocks, e.g.:

public IEnumerable<string> GetLines(string file)
{
    using (TextReader reader = File.OpenText(file))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

In the above code, you really want the file to be closed when you finish iterating, and the compiler implements IDisposable cunningly to make that work.

Jon Skeet
+1 for the Dispose discussion. Good stuff.
Fredrik Mörk