Query syntax is the sentence. Method syntax is what the compiler actually turns that sentence into.
Take one more look at every single code example before this lesson — Where, Select, OrderBy, GroupBy, Join, Sum, ToList. Every one of them, all the way back to the very first lesson of this module, has been method syntax: extension methods, chained one after another with dots, each taking a lambda. It's time to name that pattern explicitly, show exactly how the previous lesson's query syntax collapses down into it, and settle why this is the style you'll reach for in practice, day to day.
This lesson covers the fluent .Where().Select() chain, walks through the exact compiler translation from query syntax into method syntax, explains why method syntax is the more common, idiomatic choice, and closes with a full side-by-side comparison table.
Method syntax is writing a LINQ query as a chain of extension method calls — source.Where(predicate).Select(selector).OrderBy(keySelector) — each one taking the sequence before it as its input and a lambda describing what to do, and handing back a new sequence for the next call in the chain.
Every LINQ operator you've used in this module — Where, Select, OrderBy, GroupBy, Join, Sum, ToList, all of them — is an extension method defined in the static System.Linq.Enumerable class, extending IEnumerable<T>. Extension methods (from Intermediate Part III) are what make the fluent, dot-chained style possible at all: each call returns a type that itself has more of these extension methods available, letting you keep chaining indefinitely without ever needing intermediate variables.
Method syntax isn't a competing alternative invented alongside query syntax for variety's sake — it's the actual, underlying mechanism. Every LINQ operator is a method; query syntax is what got layered on top, later, as a convenience:
// This is the ACTUAL foundation — every LINQ operator, always, is a method call
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate);
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, TResult> selector);Method syntax exists because it's simply how C# extension methods work, and it covers every LINQ operator without exception — including the many operators (Distinct, Take, Skip, Count(), ToList(), and dozens more) that the previous lesson noted have no dedicated query-syntax keyword at all. Query syntax is a convenience the compiler builds by generating calls to exactly these same methods — it's an addition to method syntax, not a replacement for it.
products
.Where(p => p.Stock > 0)
.OrderBy(p => p.Price)
.Select(p => p.Name)from clause become the object every subsequent method call is chained off of.where clause becomes its own chained .Where(...) call, wrapping a lambda built from the range variable and the condition.orderby clause becomes OrderBy; every comma-separated key after it becomes a chained ThenBy, exactly matching the rule from the Sorting lesson.select clause becomes a .Select(...) call — unless it's a trivial select p with no transformation, in which case the compiler is smart enough to omit the redundant Select call entirely.Here's the exact query expression from the previous lesson, followed by exactly what the compiler rewrites it into:
// Query syntax — what YOU write
var affordable =
from p in products
where p.Price < 100 && p.Stock > 0
orderby p.Price
select new { p.Name, p.Price };// Method syntax — what the COMPILER actually generates
var affordable = products
.Where(p => p.Price < 100 && p.Stock > 0)
.OrderBy(p => p.Price)
.Select(p => new { p.Name, p.Price });Code → Meaning → Result: Every clause maps to exactly one method call, in the same order it appeared. This isn't an approximation or "roughly equivalent" — it's the literal, mechanical output the compiler produces, and it's why the two versions run identically, with identical performance, as the previous lesson established.
// Start simple
var q1 = products.Where(p => p.Stock > 0);
// Add sorting
var q2 = products.Where(p => p.Stock > 0).OrderBy(p => p.Price);
// Add projection
var q3 = products
.Where(p => p.Stock > 0)
.OrderBy(p => p.Price)
.Select(p => p.Name);
// Force execution — the ENTIRE chain runs in one pass, right here
List<string> names = q3.ToList();This incremental, dot-by-dot growth is exactly the shape deferred execution was built for — each additional method call just wraps another lazy layer around the one before it, at essentially no cost, until something finally enumerates the whole thing.
Method syntax's ability to interleave operators that have no query-syntax keyword at all — pagination, in this case — is exactly why it's the default in real production code:
public record Employee(int Id, string Name, string Department, decimal Salary);
List<Employee> PageOfHighEarners(List<Employee> employees, int pageNumber, int pageSize)
{
return employees
.Where(e => e.Salary > 80000m) // Where — has a query-syntax keyword
.OrderByDescending(e => e.Salary) // orderby — has a query-syntax keyword
.Skip((pageNumber - 1) * pageSize) // Skip — NO query-syntax keyword
.Take(pageSize) // Take — NO query-syntax keyword
.ToList(); // ToList — NO query-syntax keyword
}
var page1 = PageOfHighEarners(employees, pageNumber: 1, pageSize: 10);Three of the five operators in this realistic pagination method — Skip, Take, and ToList — simply don't exist in query syntax. Writing this in query syntax would mean starting with from/where/orderby and then still dropping into method syntax for the rest anyway. Since method syntax alone can express the entire thing cleanly, and consistently, most teams write LINQ this way by default rather than switching styles mid-expression.
Picture a factory assembly line: a part enters, station one trims it, station two paints it, station three inspects it, and it exits at the end. Each method call in a chain is one station — it receives whatever the previous station produced, does exactly one job, and passes its output to the next. You can add a station, remove one, or reorder them, and the line still reads top to bottom (or in this case, left to right) as a clear sequence of transformations. That's method syntax: a pipeline you build one dot at a time.
products.Where(predicate) is compiler sugar for Enumerable.Where(products, predicate) — extension methods let a static method be called as if it belonged to the object, which is exactly what makes the dot-chaining style possible..Select(...) after .Where(...) doesn't run Where first and then hand a finished list to Select — it builds a Select-iterator that, when pulled, pulls from the Where-iterator underneath it, which pulls from the source. The chain executes item-by-item, outermost call pulling innermost, only once something finally enumerates it.Select(p => p.Name) knows p is a Product because Where returned IEnumerable<Product>, and the compiler tracks that the whole way down the chain without you ever writing a type argument explicitly.Method syntax being the day-to-day default doesn't make query syntax wrong or deprecated — it's a fully supported, actively maintained part of the C# language, and it genuinely reads better for joins and grouping, exactly as the previous lesson showed. "Idiomatic" here means "what you'll see most often in the wild," not "the only acceptable choice."
New developers sometimes assume a five-call chain must be harder to read than the equivalent loop. In practice, each method name in a well-written chain (Where, OrderBy, Select) states its intent directly, whereas a hand-written loop bundles filtering, sorting, and transforming logic together inside one block, which a reader has to mentally untangle. A method chain, formatted with one call per line as shown throughout this lesson, is often more scannable than the loop it replaces.
var r = products.Where(p => p.Stock > 0).OrderBy(p => p.Category).ThenBy(p => p.Price).Select(p => new { p.Name, p.Price }).ToList(); all on one line, forcing a reader to scan horizontally to find each step. Break each chained call onto its own line, as every example in this lesson does — it costs nothing and makes each transformation step immediately scannable top to bottom.
.Where(p => p.Stock > 0 && p.Price < 100 && SomeComplexBusinessRule(p) && p.Category != "Discontinued") — a predicate this dense is hard to scan inline. Extract it into a well-named local function or method: .Where(IsAvailableAndAffordable) — the chain stays readable, and the logic gets a name that documents itself.
Take, Skip, Distinct, Count(), ToList(), and many more.join or grouping with multiple steps — the previous lesson's territory.| Goal | Query Syntax | Method Syntax |
|---|---|---|
| Filter only | from p in products |
products.Where(p => p.Stock > 0) |
| Filter + project | from p in products |
products |
| Multi-key sort | from e in employees |
employees |
| Group + aggregate | from e in employees |
employees |
| Take page of results | no query-syntax keyword — must drop into method syntax | products.OrderBy(p => p.Price).Skip(10).Take(10) |
Where, Select, OrderBy, and the rest — each one built on IEnumerable<T>.Take, Skip, Distinct, ToList, and more.You've learned how method syntax works and how query syntax compiles down into it. Let's check your understanding.
1. What is the actual relationship between query syntax and method syntax?
Correct: B
Why B is correct: As shown throughout How It Works and Under the Hood, the C# compiler mechanically rewrites every query expression into the equivalent chain of extension method calls — method syntax isn't an alternative, it's what query syntax actually becomes.
Why A is incorrect: There is exactly one implementation — System.Linq.Enumerable's methods — that both styles ultimately call.
Why C is incorrect: Both styles remain fully supported, current C# — neither is deprecated or being phased out.
Why D is incorrect: Both styles work over any IEnumerable<T> source, arrays and List<T> included.
Reinforcement: Method syntax is the bedrock; query syntax is a convenience layered on top of it.
2. from e in employees orderby e.Department, e.Salary descending select e — what does this compile down to in method syntax?
Correct: B
Why B is correct: As shown in How It Works and the comparison table, the first key in a comma-separated orderby clause becomes OrderBy, and every subsequent key becomes a chained ThenBy/ThenByDescending — never a second, independent OrderBy.
Why A is incorrect: As the Sorting lesson established, a second OrderBy would discard the department ordering entirely — this is exactly the wrong translation.
Why C is incorrect: This has nothing to do with sorting — it misapplies Where and Select to a completely different purpose.
Why D is incorrect: The original query never groups anything — it sorts individual employees by two keys, it doesn't bucket them.
Reinforcement: A multi-key orderby clause always translates to one OrderBy followed by ThenBy calls, matching the rule from the Sorting lesson exactly.
3. Why is method syntax generally considered more idiomatic for everyday C# code than query syntax?
Correct: B
Why B is correct: As explained in Why Does It Exist? and When Should I Use It?, method syntax's universal coverage — including operators like Take, Skip, and ToList that have no query-syntax equivalent — is why it functions as a single, consistent default rather than a style you have to switch out of partway through a query.
Why A is incorrect: Both styles compile to identical IL, as the previous lesson established — there is no performance difference.
Why C is incorrect: Query syntax remains a fully supported, current part of C# — it hasn't been removed from anything.
Why D is incorrect: Both styles work equally well with IQueryable<T> — neither is a requirement specific to it.
Reinforcement: Consistency and universal operator coverage — not speed — are why method syntax dominates day-to-day LINQ code.
4. Which of these operators has NO dedicated query-syntax keyword, meaning it must always be written in method syntax?
Correct: C
Why C is correct: As shown in the comparison table's final row, there is no take keyword in query syntax — pagination-style operators like Take and Skip must always be written in method syntax, even inside an otherwise query-syntax-heavy expression.
Why A, B, and D are incorrect: where, orderby, and select all have direct query-syntax keywords, covered throughout the previous lesson and reflected in the comparison table.
Reinforcement: Whenever a query needs an operator without a keyword, method syntax fills the gap — this is completely normal, not an exception to work around.
You now understand both LINQ syntaxes, and how they relate. Next up: writing your own LINQ-style extension method that snaps into a chain exactly like Where and Select do.
dotnetmadeeasy.com — Learn C# and .NET, the right way.