List<T>
is an IEnumerable<T>
. When you are iterating through your List<T>
, you are performing the same sequence of operations as you are for any other IEnumerable<T>
:
- Get an
IEnumerator<T>
. - Invoke
IEnumerator<T>.MoveNext()
on your enumerator. - Take the
IEnumerator<T>.Current
element from the IEnumerator interface whileMoveNext()
returnstrue
. - Dispose of the
IEnumerator<T>
.
What we know about List<T>
is that it is an in-memory collection, so the MoveNext()
function on its enumerator is going to be very cheap. It looks like your collection gives an enumerator whose MoveNext()
method is more expensive, perhaps because it is interacting with some external resource such as a database connection.
When you call ToList()
on your IEnumerable<T>
, you are running a full iteration of your collection and loading all of the elements into memory with that iteration. This is worth doing if you expect to be iterating through the same collection multiple times. If you expect to iterate through the collection only once, then ToList()
is a false economy: all it does is to create an in-memory collection that will later have to be garbage collected.