LINQ
C#
Programming
Code Explanation
Query Syntax

How does the following LINQ statement work?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

LINQ (Language Integrated Query) is a C# feature that provides a unified syntax for querying data from various sources — arrays, lists, databases, XML, and more. LINQ statements come in two forms: query syntax (SQL-like from...where...select) and method syntax (chained extension methods like .Where().Select()). Both compile to the same underlying method calls. Understanding how LINQ works means understanding deferred execution, lambda expressions, and the IEnumerable<T> / IQueryable<T> interfaces.

Query Syntax Explained

A typical LINQ query syntax statement:

csharp
1int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
2
3var evenNumbers = from n in numbers
4                  where n % 2 == 0
5                  select n;
6
7foreach (var n in evenNumbers)
8    Console.Write($"{n} "); // 2 4 6 8 10

Breaking it down:

  • from n in numbers — declares a range variable n that iterates over each element in numbers
  • where n % 2 == 0 — filters elements, keeping only those where the condition is true
  • select n — specifies what to return for each matching element

Equivalent Method Syntax

The compiler translates query syntax into method syntax:

csharp
1// Query syntax
2var result1 = from n in numbers
3              where n % 2 == 0
4              select n;
5
6// Method syntax (equivalent)
7var result2 = numbers.Where(n => n % 2 == 0);
8
9// Both produce identical results

For more complex queries:

csharp
1// Query syntax with ordering and projection
2var result = from p in people
3             where p.Age >= 18
4             orderby p.Name
5             select new { p.Name, p.Age };
6
7// Method syntax equivalent
8var result = people
9    .Where(p => p.Age >= 18)
10    .OrderBy(p => p.Name)
11    .Select(p => new { p.Name, p.Age });

Deferred Execution

LINQ queries are not executed when defined — they execute when iterated:

csharp
1var numbers = new List<int> { 1, 2, 3, 4, 5 };
2
3// Query is defined but NOT executed yet
4var query = numbers.Where(n => n > 3);
5
6numbers.Add(6); // Modify the source after defining the query
7
8// Query executes NOW when iterated
9foreach (var n in query)
10    Console.Write($"{n} "); // 4 5 6 — includes 6!

The query re-executes each time it is iterated. To capture results at a specific point, materialize with .ToList() or .ToArray():

csharp
var snapshot = numbers.Where(n => n > 3).ToList(); // Executes immediately
numbers.Add(7);
// snapshot still contains {4, 5, 6} — not affected by adding 7

Common LINQ Operations

Filtering

csharp
var adults = people.Where(p => p.Age >= 18);

Projection (Transform)

csharp
var names = people.Select(p => p.Name);

var anonymousObjects = people.Select(p => new { p.Name, IsAdult = p.Age >= 18 });

Ordering

csharp
var sorted = people.OrderBy(p => p.Name);
var descending = people.OrderByDescending(p => p.Age);
var multiSort = people.OrderBy(p => p.LastName).ThenBy(p => p.FirstName);

Aggregation

csharp
1int count = numbers.Count();
2int sum = numbers.Sum();
3double avg = numbers.Average();
4int max = numbers.Max();
5int min = numbers.Min();
6
7// With condition
8int adultCount = people.Count(p => p.Age >= 18);

Grouping

csharp
1var byDepartment = from p in people
2                   group p by p.Department into g
3                   select new { Department = g.Key, Count = g.Count() };
4
5// Method syntax
6var byDept = people
7    .GroupBy(p => p.Department)
8    .Select(g => new { Department = g.Key, Count = g.Count() });

Joining

csharp
1var result = from o in orders
2             join c in customers on o.CustomerId equals c.Id
3             select new { c.Name, o.Total };
4
5// Method syntax
6var result = orders.Join(
7    customers,
8    o => o.CustomerId,
9    c => c.Id,
10    (o, c) => new { c.Name, o.Total });

How the Compiler Processes LINQ

The compiler transforms query syntax into extension method calls defined in System.Linq.Enumerable (for IEnumerable<T>) or System.Linq.Queryable (for IQueryable<T>):

csharp
1// What you write
2var result = from n in numbers where n > 5 select n * 2;
3
4// What the compiler generates
5var result = numbers.Where(n => n > 5).Select(n => n * 2);
6
7// For IQueryable (Entity Framework), lambdas become expression trees
8IQueryable<int> dbResult = dbNumbers.Where(n => n > 5).Select(n => n * 2);
9// Expression tree is translated to SQL: SELECT n * 2 FROM Numbers WHERE n > 5

First, Single, and Default Variants

csharp
1var numbers = new List<int> { 1, 2, 3, 4, 5 };
2
3int first = numbers.First();              // 1 (throws if empty)
4int firstOrDefault = numbers.FirstOrDefault(); // 1 (returns 0 if empty)
5int firstEven = numbers.First(n => n % 2 == 0); // 2
6
7int single = numbers.Single(n => n == 3);       // 3 (throws if 0 or 2+ matches)
8int singleOrDefault = numbers.SingleOrDefault(n => n == 99); // 0
9
10bool any = numbers.Any(n => n > 3);   // true
11bool all = numbers.All(n => n > 0);   // true

Common Pitfalls

  • Multiple enumeration of a deferred query: Each foreach or LINQ operation on a deferred query re-executes it. If the query is expensive (database call), materialize it with .ToList() first to avoid redundant execution.
  • Confusing First() with Single(): First() returns the first match and ignores duplicates. Single() throws if there are zero or multiple matches. Use Single() when exactly one result is expected.
  • Modifying a collection during LINQ iteration: Adding or removing elements from a List<T> while iterating with foreach throws InvalidOperationException. Materialize with .ToList() before modifying the source.
  • Using query syntax for simple operations: Query syntax is verbose for single-method operations like filtering. numbers.Where(n => n > 5) is cleaner than from n in numbers where n > 5 select n for simple cases.
  • Assuming LINQ is always lazy: Methods like .ToList(), .ToArray(), .Count(), .Sum(), .First(), and .Single() execute the query immediately. Only chained .Where(), .Select(), .OrderBy() are deferred.

Summary

  • LINQ query syntax (from...where...select) compiles to extension method calls (.Where().Select())
  • Queries use deferred execution — they run when iterated, not when defined
  • Use .ToList() or .ToArray() to materialize results and prevent re-execution
  • IEnumerable<T> LINQ runs in memory; IQueryable<T> LINQ translates to SQL via expression trees
  • Both query syntax and method syntax produce identical results — choose based on readability

Course illustration
Course illustration

All Rights Reserved.