This is because IEnumerable
s are evaluated only when you perform an operation on them that forces them to become concreted. You can store a collection of IEnumerable
, all of which have .Select()
operations that use a value from the current scope (in this case i
) and it may be different depending on what value it holds at the point that it's evaluated.
Every iteration of your loop ends with a call to string.Join
which forces what's in itemRows
to become concrete and evaluate the value of i
, and that includes all previous entries in itemRows
, so the value of i
will just be what it is at that point in time for all IEnumerable
s in the list. This is why every row refers to the current value of i
and not the value that i
had when the .Select()
operation was declared.
If you .ToList()
on items
before adding to itemRows
then you'll have a List<List<Item>>
that you'll be covariant-ly referring to by List<IEnumerable<Item>>
. This means that the .Select()
on items
is evaluated/concreted once before adding to itemRows
, rather than on every call to string.Join
.