Question

Please consider the following C# block:

int resultIndex = 0;

Result firstResult = results.First();
DoAVeryImportOperationWithFirstResult(firstResult);

Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
yield return firstResult;

foreach(Result result in results)
{
   Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
   yield return result;
}

If you are familiarized with Linq and Iterators, you'll notice that in the first iteration of the foreach block, the first result from results will be returned instead of the second one.

So, basically this is my problem: I can't get the first value from the iterator method then use it somewhere else without restarting this method.

Someone know some workaround for this?

Was it helpful?

Solution

Others have shown the approach using a foreach loop and conditional execution. That's actually a neat approach - but here's another option in case the foreach loop is inappropriate for whatever reason.

using (var iterator = results.GetEnumerator())
{
    if (!iterator.MoveNext())
    {
        // Throw some appropriate exception here.
    }

    Result firstResult = iterator.Current;
    DoAVeryImportOperationWithFirstResult(firstResult);

    Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
    yield return firstResult;

    while (iterator.MoveNext())
    {
        Result result = iterator.Current;
        Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
        yield return result;
    }
}

OTHER TIPS

Just do it explicitly:

bool first = true;
foreach(var item in results) {
    if(first) {
        first = false;
        // whatever
    } else {
        // whatever else
    }
}

or more complex:

using(var iter = results.GetEnumerator()) {
    if(iter.MoveNext()) {
        // do first things with iter.Current

        while(iter.MoveNext()) {
            // do non-first things with iter.Current
        }
    }
}

You need to iterate manually:

var enumerator = results.GetEnumerator();
enumerator.MoveNext();
yield return enumerator.Current; //first
while(enumerator.MoveNext())
 yield return enumerator.Current; //2nd, ...

All error checking omitted... Also don't forget to dispose.

bool isFirst = true;
foreach(Result result in results)
{
   if(isFirst)
   {
      DoAVeryImportOperationWithFirstResult(firstResult);
      isFirst = false;
   }

   Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
   yield return result;
}

You need to use Skip

foreach(Result result in results.Skip(1))
{
   Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
   yield return result;
}

or manually iterate over the results.

If you think about how iterators are implemented what you are seeing is indeed the expected behavior!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top