GetNumbersWrapped
simply 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.
GetNumbersWrappedYield
adds an extra layer of abstraction - so now, every call to MoveNext
has 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 GetNumbersWrappedYield
does do is prevent abuse by callers. For example, if GetNumbers
was:
private IEnumerable<int> GetNumbers(int x)
{
return myPrivateSecretList;
}
then callers of GetNumbersWrapped
can abuse this:
IList list = (IList)GetNumbers(4);
list.Clear();
list.Add(123); // mwahahaahahahah
However, callers of GetNumbersWrappedYield
cannot 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.