gotchacsharpdotnetModerate
LINQ deferred execution: query evaluated multiple times on multiple enumerations
Viewed 0 times
LINQ deferred executionmultiple enumerationToList ToArrayIQueryable double queryIEnumerable lazy evaluation
Problem
LINQ queries over IEnumerable<T> are lazy. Enumerating the same query variable twice executes the query twice — potentially hitting the database twice, producing different results, or being very slow for large in-memory sequences.
Solution
Materialize with ToList() or ToArray() when you need to enumerate multiple times or guarantee a point-in-time snapshot:
// BAD — query evaluated twice
var query = _db.Orders.Where(o => o.Status == OrderStatus.Pending);
var count = query.Count(); // executes SQL
var list = query.ToList(); // executes SQL again
// GOOD — materialize once
var pending = await _db.Orders
.Where(o => o.Status == OrderStatus.Pending)
.ToListAsync();
var count = pending.Count; // in-memory, no DB call
// BAD — side effects run twice
var processed = items.Select(i => { Process(i); return i; });
foreach (var _ in processed) { } // Process called for each item
foreach (var _ in processed) { } // Process called again!Why
IEnumerable<T> LINQ operators build an iterator state machine. Each call to GetEnumerator() restarts execution from the source. For EF Core queries, this means a new database roundtrip per enumeration.
Gotchas
- IQueryable<T> defers until GetEnumerator, ToList, Count, First, etc. are called
- yield return methods return IEnumerable — every foreach re-runs the generator body
- Count() on IList<T> is O(1) but on IEnumerable<T> enumerates the whole sequence — use .Count property when available
Revisions (0)
No revisions yet.