I often find the scenario where I return an IEnumerable using the yield return statement, then have other methods which call this function with different parameters and directly return the result.
Is there any performance benefit to iterating through the results end yield returning these as opposed to simply returning the collection? i.e. if I use return on the resulting IEnumberable rather than looping through these results again and using yield return does the compiler know to only generate the results as they're required, or does it wait for the entire collection to be returned before returning all results?
public class Demo
{
private IEnumerable<int> GetNumbers(int x)
{
//imagine this operation were more expensive than this demo version
//e.g. calling a web service on each iteration.
for (int i = 0; i < x; i++)
{
yield return i;
}
}
//does this wait for the full list before returning
public IEnumerable<int> GetNumbersWrapped()
{
return GetNumbers(10);
}
//whilst this allows the benefits of Yield Return to persist?
public IEnumerable<int> GetNumbersWrappedYield()
{
foreach (int i in GetNumbers(10))
yield return i;
}
}
GetNumbersWrappedsimply passes through the original enumerable - it hasn't even invoked the iterator at that point. The end result remains fully deferred / lazy / spooling / whatever else.GetNumbersWrappedYieldadds an extra layer of abstraction - so now, every call toMoveNexthas to do ever so slightly more work; not enough to cause pain. It too will be fully deferred / lazy / spooling / whatever else - but adds some minor overheads. Usually these minor overheads are justified by the fact that you are adding some value such as filtering or additional processing; but not really in this example.Note: one thing that
GetNumbersWrappedYielddoes do is prevent abuse by callers. For example, ifGetNumberswas:then callers of
GetNumbersWrappedcan abuse this:However, callers of
GetNumbersWrappedYieldcannot do this... at least, not quite as easily. They could, of course, still use reflection to pull the iterator apart, obtain the wrapped inner reference, and cast that.This, however, is not usually a genuine concern.