Query syntax and method syntax

The two spellings of LINQ, how the compiler rewrites one into the other, and which to reach for in a given situation.

One query, two spellings

LINQ is a set of extension methods on IEnumerable<T> and IQueryable<T>. Query syntax is the SQL-like form the C# compiler translates into those methods; method syntax is the direct call chain. They produce identical results.

// query syntax
var query =
    from o in orders
    where o.Total > 100
    orderby o.Total descending
    select new { o.Id, o.Customer, o.Total };

// method syntax - exactly what the compiler emits for the above
var method = orders
    .Where(o => o.Total > 100)
    .OrderByDescending(o => o.Total)
    .Select(o => new { o.Id, o.Customer, o.Total });
ClauseEquivalent method
from x in srcThe source itself
whereWhere
selectSelect
orderbyOrderBy / OrderByDescending / ThenBy
join ... on ... equals ...Join
group ... byGroupBy
letSelect introducing an intermediate value
intoFeeds the result of one clause into a continuation
  • Query syntax must start with from and end with select or group.
  • Query syntax supports one let, join and group per clause naturally; anything beyond becomes nested and less readable.
  • A query that only calls Where or only Select is shorter in method syntax.

Joins, let and grouping

// inner join: customers with at least one order
var report =
    from c in customers
    join o in orders on c.Id equals o.CustomerId
    let isLarge = o.Total > 500
    orderby c.Name, o.Total descending
    select new { c.Name, o.Id, o.Total, isLarge };

// group join: every customer, with their orders (possibly none)
var withOrders =
    from c in customers
    join o in orders on c.Id equals o.CustomerId into ordersForCustomer
    select new
    {
        c.Name,
        Count = ordersForCustomer.Count(),
        Spend = ordersForCustomer.Sum(x => x.Total)
    };
// group by one key
var byCountry = orders
    .GroupBy(o => o.Country)
    .Select(g => new
    {
        Country = g.Key,
        Orders = g.Count(),
        Revenue = g.Sum(o => o.Total)
    })
    .OrderByDescending(x => x.Revenue)
    .ToList();

// grouping by a composite key and shaping each group
var byMonth = orders
    .GroupBy(o => new { o.Country, Month = o.Placed.Month })
    .Select(g => new
    {
        g.Key.Country,
        g.Key.Month,
        Top = g.OrderByDescending(o => o.Total).First().Id
    });
💡
join ... into is a group join, not a left outer join by accident: it produces one row per left element with a sequence of matches. If you want a flat left join, group join then SelectMany with DefaultIfEmpty().

Choosing a form

// left outer join in method syntax
var leftJoin = customers
    .GroupJoin(orders, c => c.Id, o => o.CustomerId,
        (c, os) => new { Customer = c, Orders = os })
    .SelectMany(
        x => x.Orders.DefaultIfEmpty(),
        (x, o) => new { x.Customer.Name, OrderId = o?.Id, Total = o?.Total ?? 0 });

// the same outer join is clearer in query syntax
var leftJoinQuery =
    from c in customers
    join o in orders on c.Id equals o.CustomerId into os
    from o in os.DefaultIfEmpty()
    select new { c.Name, OrderId = o?.Id, Total = o?.Total ?? 0 };
SituationPrefer
Multi-source join with filtersQuery syntax
Single chain of Where / SelectMethod syntax
Custom operators or third-party extensionsMethod syntax (query syntax cannot call them)
Mixing query result into a larger expressionMethod syntax
Complex grouping and shapingQuery syntax

The rule that holds up in review: use query syntax where the structure is relational and method syntax everywhere else. Do not mix both inside one expression — a reader has to re-parse the shape twice.

FAQ

Is one form faster than the other?
No. Query syntax is translated to the same method calls at compile time, so the IL is equivalent. Choose on readability alone.
Why does my query syntax not compile after I add a custom method?
Query syntax only understands a fixed set of clauses. Insert the custom call with parentheses — (from x in src select x).MyExtension() — or switch that query to method syntax.

Common LINQ operators Deferred execution and querying a database

Last refreshed 2026-09-18.