The key to answering this is deferred execution. When you do this
items = items.Select(item => items.First(i => i == item));
you do not iterate the items
array passed into the method. Instead, you assign it a new IEnumerable<int>
, which references itself back, and starts iterating only when the caller starts enumerating the results.
That is why all your other fixes have dealt with the problem: all you needed to do is to stop feeding IEnumerable<int>
back to itself:
- Using
var foo
breaks self-reference by using a different variable, - Using
return items.Select...
breaks self-reference by not using intermediate variables at all, - Using
ToList()
breaks self-reference by avoiding deferred execution: by the timeitems
is re-assigned, olditems
has been iterated over, so you end up with a plain in-memoryList<int>
.
But if it’s feeding on itself, how does it get anything at all?
That’s right, it does not get anything! The moment you try iterating items
and ask it for the first item, the deferred sequence asks the sequence fed to it for the first item to process, which means that the sequence is asking itself for the first item to process. At this point, it’s turtles all the way down, because in order to return the first item to process the sequence must first get the first item to process from itself.