ToList() and ToArray() run the recipe once and keep the result. From then on you have a
collection, and enumerating it a hundred times costs nothing extra.
Two enumerations, two costs
Recipe — runs per use
C#
IEnumerable<int> seq = Source();
var count = seq.Count(); // run 1
var total = seq.Sum(); // run 2
foreach (var n in seq) // run 3
{
Console.WriteLine(n);
}Result — runs once
C#
List<int> seq = Source().ToList();
var count = seq.Count; // no run
var total = seq.Sum(); // no run
foreach (var n in seq) // no run
{
Console.WriteLine(n);
}The right-hand version pays for the whole sequence up front and gives up laziness. That is the trade, and it is the correct one whenever you will look at the data more than once.
A rule that holds up
- Returning a sequence from a method — prefer
IEnumerable<T>, so the caller decides. - Using a sequence more than once — materialise it first.
- Passing a sequence to code you do not control — materialise it, unless laziness is the point.
The awkward middle case is a method that returns IEnumerable<T> from a live resource. If the
caller might enumerate twice, either document it loudly or return a List<T> and be honest about
what you built.
Try it: Task 2
Open the editorTry it: Task 3
Open the editor