Skip to content

Chapter 4 of 7

LINQ and Data Querying

LINQ (Language Integrated Query) lets you write query expressions directly in C# to filter, sort, and transform data from collections, databases, and XML. There are two equivalent syntaxes: query syntax resembles SQL with from, where, select, and orderby clauses, while method syntax uses extension methods like Where, Select, and OrderBy chained with dot notation. Both compile to the same IL code, so the choice is mostly stylistic. Most LINQ operators return IEnumerable, and a key characteristic is deferred execution: a query is not executed when defined, but only when its results are enumerated, such as inside a foreach loop, a ToList() call, or a Count() call. The yield return statement enables iterator methods that produce values one at a time, lazily, with the compiler generating a state machine and yield break terminating the iterator early. IEnumerable is the base interface for all generic collections that can be enumerated and is what enables both foreach and LINQ.

The core operators form a small, composable vocabulary. Select projects each element into a new form, essentially a map operation. Where filters elements based on a predicate. OrderBy and ThenBy produce a sorted sequence. GroupBy groups elements by a key, returning IEnumerable> where each group exposes its Key and the contained elements. Aggregate applies an accumulator function over a sequence, similar to reduce or fold in functional languages, and is useful for custom accumulation beyond what Sum and Count provide. Cast attempts to cast every element to T and throws on the first mismatch, while OfType keeps only elements of the target type, skipping the rest, which is the right tool when filtering a non-generic legacy collection.

LINQ also supports more advanced shapes. Join pairs elements by a key, like SQL's INNER JOIN, while Zip pairs elements positionally and stops at the shorter sequence. SelectMany flattens nested sequences: orders.SelectMany(o => o.Items) returns a single IEnumerable, while orders.Select(o => o.Items) returns IEnumerable>, which is rarely what you want. SelectMany is essential for one-to-many projections and chaining inner queries.

A critical distinction is between IEnumerable and IQueryable. IEnumerable represents an in-memory sequence where filtering happens client-side, while IQueryable builds an expression tree that can be translated to another query language (typically SQL) and executed server-side, often with significant performance benefits when working with databases; the same method syntax is used in both cases, but the execution location is fundamentally different. For materializing results, ToList returns a mutable List, while ToArray returns a fixed-size T[]; both force enumeration and are O(n). For single-element queries, First throws on an empty sequence, FirstOrDefault returns default(T), Single throws on zero or more than one element, and SingleOrDefault returns default(T) only if the sequence is empty; use Single when you expect exactly one match.

All chapters
  1. 1Type System and Language Fundamentals
  2. 2Functions, Delegates, and Events
  3. 3Modern C# Language Features
  4. 4LINQ and Data Querying
  5. 5Asynchronous and Parallel Programming
  6. 6Memory, Performance, and Strings
  7. 7Collections, Concurrency, Resources, and Diagnostics

Drill it

Reading is not remembering. These come from the Csharp Programming deck:

Q

What is LINQ in C#?

LINQ (Language Integrated Query) is a set of features that allows you to write query expressions directly in C# to filter, sort, and transform data from collect...

Q

What is the difference between LINQ query syntax and method syntax?

Query syntax resembles SQL:var q = from x in list where x > 5 select x;Method syntax uses extension methods:var q = list.Where(x => x > 5);Both compile to the s...

Q

What does the LINQ Select method do?

Select projects each element of a sequence into a new form (a transformation/map operation).var names = people.Select(p => p.Name);It returns an IEnumerable<...

Q

What is deferred execution in LINQ?

Deferred execution means a LINQ query is not executed when defined, but only when the results are enumerated (e.g., via foreach, ToList(), or Count()). This all...