100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C#

Filtering with Where

Learn how LINQ's Where operator filters sequences using predicates, how deferred execution affects when the filter actually runs, and how to combine multiple conditions safely.

Core OperatorsBeginner9 min readJul 10, 2026
Analogies

What Is the Where Operator?

Where() is LINQ's core filtering operator: it takes a Func<T, bool> predicate and returns a new IEnumerable<T> containing only the elements for which the predicate evaluates to true. Unlike a hand-written foreach loop with an if-check, Where() is declarative — you describe the condition you want, not the mechanics of iterating and collecting matches, and the same predicate works identically whether the source is an in-memory List<T> or, via IQueryable<T>, a remote database table translated into SQL.

🏏

Cricket analogy: A selector picking the playing XI from a squad of 20 applies one clear rule — 'must have a batting average above 35' — and keeps only players who satisfy it, just like Where() keeps only elements matching its predicate.

Deferred Execution and Lazy Evaluation

Calling Where() does not immediately filter anything — it builds an iterator object that captures the source and the predicate but only actually evaluates elements when something enumerates the result, such as a foreach loop, ToList(), or another LINQ operator pulling from it. This is called deferred execution, and it means the source is checked at enumeration time, not at the moment Where() was written in code; if the underlying collection changes between the Where() call and the foreach, the loop sees the updated data, which can be either useful or a source of subtle bugs.

🏏

Cricket analogy: Setting a fielding restriction rule for the powerplay doesn't select any specific fielders until the over actually starts — the rule only takes effect the moment play begins, just as Where() only evaluates its predicate when the sequence is actually enumerated.

Combining and Chaining Predicates

You can express multiple conditions either by combining them inside a single lambda with && and || (e.g., Where(o => o.Status == "Shipped" && o.Total > 100)), or by chaining separate Where() calls (Where(o => o.Status == "Shipped").Where(o => o.Total > 100)); both produce identical results because LINQ-to-Objects short-circuits on the first false condition, but for IQueryable sources translated to SQL, the query provider typically merges chained Where() calls into a single WHERE clause with AND, so readability, not performance, usually drives the choice between the two styles.

🏏

Cricket analogy: A DRS review checks 'was it out AND was it in time' as one combined ruling rather than two separate reviews, similar to how Where(o => a && b) evaluates a compound condition in a single predicate pass.

The Indexed Overload

Where() has a lesser-used overload, Where(Func<T, int, bool>), that passes the zero-based index of each element alongside the value, letting you write predicates like Where((item, index) => index % 2 == 0) to keep every other element; this overload is convenient for position-dependent filtering but should be used carefully on IQueryable sources, since most database providers cannot translate the index parameter into SQL and will throw at runtime.

🏏

Cricket analogy: Selecting only the odd-numbered overs for a highlights reel — over 1, over 3, over 5 — requires tracking the over's position, not just its content, just like Where()'s indexed overload filters based on an element's position in the sequence.

csharp
var orders = new List<Order>
{
    new Order { Id = 1, Status = "Shipped", Total = 120.50m },
    new Order { Id = 2, Status = "Pending", Total = 45.00m },
    new Order { Id = 3, Status = "Shipped", Total = 89.99m },
    new Order { Id = 4, Status = "Shipped", Total = 210.00m },
};

// Basic filtering with a single predicate
var shipped = orders.Where(o => o.Status == "Shipped");

// Combined condition inside one lambda
var bigShippedOrders = orders.Where(o => o.Status == "Shipped" && o.Total > 100);

// Equivalent result via chained Where() calls
var chained = orders.Where(o => o.Status == "Shipped")
                     .Where(o => o.Total > 100);

// Indexed overload: keep only even-positioned elements
var everyOther = orders.Where((order, index) => index % 2 == 0);

// Query syntax equivalent
var queryStyle = from o in orders
                  where o.Status == "Shipped" && o.Total > 100
                  select o;

LINQ's query syntax (from x in source where condition select x) compiles down to exactly the same Where() method calls as fluent syntax. The 'where' keyword in query syntax and the Where() extension method are interchangeable — pick whichever reads more naturally for the query you're writing.

Because Where() is deferred, re-enumerating the same query variable (e.g., iterating it twice, or calling both .Count() and .ToList() on it) re-runs the predicate against the source each time. If the predicate has side effects, or the source is an expensive IQueryable hitting a database, this can silently cause repeated work or repeated round trips — materialize with ToList() if you need to enumerate more than once.

  • Where() filters a sequence using a Func<T, bool> predicate, returning only matching elements.
  • Where() uses deferred execution — the predicate runs only when the query is enumerated, not when Where() is called.
  • Combined && conditions and chained Where() calls produce identical results in LINQ-to-Objects.
  • For IQueryable sources, chained Where() calls are typically merged into a single SQL WHERE clause.
  • The indexed overload Where((item, index) => ...) filters based on element position but rarely translates to SQL.
  • Re-enumerating a deferred Where() query re-executes the predicate; materialize with ToList() to avoid repeated work.
  • Query syntax's 'where' clause and the Where() method are functionally identical.

Practice what you learned

Was this page helpful?

Topics covered

#LINQStudyNotes#MicrosoftTechnologies#FilteringWithWhere#Filtering#Where#Operator#Deferred#StudyNotes#SkillVeris#ExamPrep