Common LINQ operators

Filtering, projection, ordering, aggregation and the element operators, with the traps that produce exceptions in production.

The operators you actually use

CategoryOperatorsNotes
FilteringWhere, OfType<T>Deferred; runs when enumerated
ProjectionSelect, SelectManySelectMany flattens one level
OrderingOrderBy, ThenBy, ReverseThenBy only after an OrderBy
GroupingGroupBy, ToLookupToLookup executes immediately
JoiningJoin, GroupJoin, ZipEquality joins only
SetDistinct, Union, Intersect, ExceptUses the default or supplied comparer
PartitioningTake, Skip, TakeWhile, ChunkOrdering must be explicit for paging
ElementFirst, Single, Last, ElementAtThrowing and *OrDefault variants differ
AggregationCount, Sum, Min, Max, Average, AggregateImmediate; empty Min on values throws
QuantifiersAny, All, ContainsShort-circuiting, unlike Count() > 0

Every operator above has a Func-based overload plus an overload taking an IEqualityComparer<T> or IComparer<T>. That second overload is how you control case-insensitive matching and domain-specific ordering.

Element and aggregation traps

// These throw on an empty or over-long sequence:
var a = nums.First();              // InvalidOperationException if empty
var b = nums.Single();             // throws unless exactly one element
var c = nums.Last();               // throws if empty
var d = nums.Max();                // throws on an empty sequence of values
var e = nums.ElementAt(10);        // ArgumentOutOfRangeException

// Safe forms with an explicit fallback:
var a2 = nums.FirstOrDefault(-1);
var b2 = nums.SingleOrDefault();
var e2 = nums.ElementAtOrDefault(10);

// Prefer Any over Count for existence - Any short-circuits:
if (orders.Any(o => o.Total > 1000)) { /* ... */ }
bool allShipped = orders.All(o => o.Shipped);

// Aggregate folds a sequence into one value
var csv = names.Aggregate((acc, n) => acc + ", " + n);
var total = orders.Aggregate(
    seed: 0m,
    func: (sum, o) => sum + o.Total,
    resultSelector: sum => Math.Round(sum, 2));
  • Single is a correctness assertion, not a convenience: it fails loudly when a uniqueness assumption is violated. Use it where duplicates would be a bug.
  • Count() > 0 enumerates the whole sequence; Any() stops at the first element. On an IQueryable both become SQL, but the cost difference remains for LINQ to Objects.
  • Average, Min and Max throw on an empty sequence for value types. Guard with Any() or project to decimal? first.
  • Chunk(n) splits a sequence into fixed-size batches, which is the clean way to build bulk inserts.

Ordering and comparers

// multi-key ordering - ThenBy extends the previous OrderBy
var sorted = people
    .OrderBy(p => p.LastName)
    .ThenBy(p => p.FirstName)
    .ThenByDescending(p => p.Hired)
    .ToList();

// case-insensitive de-duplication with an explicit comparer
var uniqueEmails = users
    .Select(u => u.Email)
    .Distinct(StringComparer.OrdinalIgnoreCase)
    .ToList();

// top N per group without sorting the whole set
var bestPerCountry = orders
    .GroupBy(o => o.Country)
    .SelectMany(g => g.OrderByDescending(o => o.Total).Take(3))
    .ToList();

// paging: Skip/Take is only stable with a deterministic order
var page3 = orders
    .OrderBy(o => o.Placed).ThenBy(o => o.Id)
    .Skip(2 * 25).Take(25)
    .ToList();
⚠️
Unordered Skip/Take is nondeterministic. Rows can repeat or vanish between page requests because the database is free to return any order. Always pair paging with a total order that includes a unique column such as the primary key.

FAQ

Is Count() or Any() better for checking emptiness?
Any(). It stops as soon as one element is found, while Count() must enumerate everything. On a database query both translate to an aggregate, but Any still produces the cheaper plan.
Why did my OrderBy change nothing?
LINQ never mutates the source; OrderBy returns a new, ordered sequence. If you discarded the return value, or the consumer re-sorts the result, the ordering is lost.

Query syntax and method syntax Deferred execution and querying a database

Last refreshed 2026-09-18.