Back to Blog
C#

C# LINQ Method Syntax Explained with Examples

c# linq method syntax: Understand how C# LINQ method syntax works: extension methods, lambda predicates, deferred execution, and when IEnumerable differs from IQueryable.

LINQC#IEnumerableIQueryableLambda ExpressionsDeferred Execution
A chain of connected nodes representing LINQ method syntax calls in C#, with one node highlighted to show a filtering step.

c# linq method syntax requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

Method Syntax Is a Chain of Extension Methods

In C#, LINQ method syntax is built from extension methods defined on System.Linq.Enumerable for in-memory collections and System.Linq.Queryable for IQueryable<T> sources. Each method takes a delegate or expression tree as its argument, and the result of one call feeds into the next. That is why a typical method-syntax query reads as a chain:

var result = numbers .Where(n => n % 2 == 0) .Select(n => n * n);

Where filters the sequence, Select projects each remaining element, and the chaining works because each method returns an IEnumerable<T> or IQueryable<T>. No query executes at this point; the chain only describes what should happen when the sequence is enumerated.

Filtering and Projecting: The Core Pattern

The two operators developers reach for most are Where and Select. Where takes a Func<T, bool> predicate and returns only the elements for which the predicate returns true. Select takes a Func<T, TResult> and maps each element to a new shape.

List<Order> orders = GetOrders(); var shippedItems = orders .Where(o => o.Status == OrderStatus.Shipped) .Select(o => new { o.Id, o.Total });

The anonymous type in the Select call keeps the projection local to the method. If the projected shape is needed elsewhere, a named record or class is the better choice, because the anonymous type cannot be used as a return type without additional machinery.

Ordering and Grouping in Method Syntax

OrderBy and OrderByDescending sort a sequence by a key. Subsequent ThenBy calls add secondary sort criteria without disturbing the primary ordering:

var ranked = players .OrderByDescending(p => p.Score) .ThenBy(p => p.Name);

GroupBy partitions a sequence into groups keyed by a value. Each group is an IGrouping<TKey, TElement> that is itself enumerable:

var byCategory = products.GroupBy(p => p.Category); foreach (var group in byCategory) { Console.WriteLine($"{group.Key}: {group.Count()} items"); }

Grouping is often the point where method syntax becomes clearer than query syntax, because the query-syntax group ... by clause requires an explicit into to continue the query, while the method chain simply continues with the next call.

Deferred Execution Changes When Code Runs

Most LINQ operators defer execution. Where, Select, OrderBy, and GroupBy return a sequence that is not evaluated until it is enumerated by foreach, ToList, ToArray, Count, or another consuming operation. This has practical consequences:

var query = numbers.Where(n => n > 10); numbers.Add(15); var result = query.ToList(); // includes 15

Because the predicate runs during enumeration, the query sees the current state of the source. This is useful when building a query incrementally, but it also means a query that is enumerated twice runs twice. If the source is expensive to produce or the predicate has side effects, materialize the result with ToList or ToArray after the first enumeration.

Operators such as Count, First, Single, and Any force immediate execution because they must consume the sequence to produce a scalar value.

Performance Considerations: IEnumerable vs IQueryable

The same method-syntax calls behave differently depending on the receiver type. On IEnumerable<T>, the LINQ methods are the Enumerable extension methods, which execute in memory. On IQueryable<T>, they are the Queryable extension methods, which build an expression tree that a provider translates into a query language such as SQL.

IQueryable<Customer> customers = dbContext.Customers; var active = customers .Where(c => c.IsActive) .Select(c => new { c.Id, c.Name }) .ToList();

With IQueryable<T>, the provider translates the whole chain into a single database query. Filtering happens in the database, not in memory. The same chain written against an IEnumerable<Customer> would load all customers and filter them on the client.

The important rule is to keep the queryable chain intact until the data is needed. Calling ToList early and then applying further LINQ operators switches execution to memory, which can pull far more rows than necessary.

Common Mistakes with Method Syntax

One recurring mistake is re-enumerating a sequence that is produced lazily. A Select that reads from a file or a Where that calls an expensive method will repeat that work on every enumeration. Materialize once when the cost is significant.

Another mistake is assuming Single and First behave the same. Single throws when the sequence contains more than one element, while First returns the first element and ignores the rest. Use Single only when the data guarantees at most one match, and use First when the first match is sufficient.

A third issue is capturing a loop variable in a lambda. Since C# 5, the loop variable in a foreach is a fresh variable per iteration, so this is no longer the trap it used to be. But a for loop variable is still shared across iterations, and capturing it in a lambda produces surprising results.

When Method Syntax Becomes Harder to Read

Long chains of Where, Select, OrderBy, and GroupBy can become dense. Splitting the chain across lines and giving intermediate results a name often improves readability:

var activeCustomers = customers.Where(c => c.IsActive); var recentOrders = orders.Where(o => o.CreatedAt > cutoff); var matches = activeCustomers.Join(recentOrders, c => c.Id, o => o.CustomerId, (c, o) => new { c.Name, o.Total });

Query syntax is a reasonable alternative when the chain involves multiple from clauses or a join that reads more naturally in SQL-like form. The two syntaxes are functionally equivalent, and a project can mix them. The decision is about readability, not capability.

c# linq method syntax: Practical Usage and Code Examples | RYUSLOG DEV