100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C#

LINQ Basics

Language Integrated Query lets you write expressive, type-safe queries directly in C# over collections, databases, and XML using a unified syntax.

LINQ & Functional FeaturesIntermediate10 min readJul 9, 2026
Analogies

LINQ Basics

LINQ (Language Integrated Query) is a set of extension methods and language keywords that let you query any object implementing IEnumerable<T> (or IQueryable<T> for remote sources like databases) using a consistent, declarative syntax. Instead of writing manual loops with mutable accumulator variables, you express what you want — filter, project, sort, group — and the runtime handles how. LINQ ships with two equivalent syntaxes: method syntax, built from chained extension methods like Where, Select, and OrderBy defined in System.Linq, and query syntax, which reads like SQL (from x in source where ... select ...) and compiles down to the very same method calls. Most professional C# code favors method syntax because it composes better with lambdas and is easier to extend with custom operators.

🏏

Cricket analogy: LINQ is like telling the scorer 'give me all centuries this series' instead of manually flipping through every scorecard; method syntax chaining Where/Select is like a fielding captain's checklist, while query syntax reads like a commentator's script but compiles to the same instructions.

Deferred Execution and Streaming

A defining trait of most LINQ operators is deferred (lazy) execution: calling Where or Select does not iterate the source immediately — it builds an iterator that only runs when you actually enumerate the result, for example with foreach, ToList(), or Count(). This means a query variable can be built once and re-evaluated later against a source that has since changed, which is powerful but also a common source of subtle bugs if you assume a query has 'already run'. Operators like ToList, ToArray, Count, and First force immediate evaluation.

🏏

Cricket analogy: A Where filter on 'all sixes hit' is like writing the query on the scoreboard but not tallying until the umpire calls for the count at innings end (ToList/Count) - and if the match continues, re-checking the tally reflects the latest overs, not the original snapshot.

csharp
var employees = new List<Employee>
{
    new("Ravi", "Engineering", 92000),
    new("Meera", "Sales", 61000),
    new("Owen", "Engineering", 105000),
    new("Priya", "Sales", 74000),
};

// Method syntax: filter, project, sort
var topEngineers = employees
    .Where(e => e.Department == "Engineering")
    .OrderByDescending(e => e.Salary)
    .Select(e => new { e.Name, e.Salary })
    .ToList();

// Equivalent query syntax
var sameResult =
    from e in employees
    where e.Department == "Engineering"
    orderby e.Salary descending
    select new { e.Name, e.Salary };

// Grouping and aggregation
var averageByDept = employees
    .GroupBy(e => e.Department)
    .Select(g => new { Department = g.Key, Avg = g.Average(e => e.Salary) });

record Employee(string Name, string Department, decimal Salary);

Common Operators

Beyond Where and Select, LINQ provides a rich vocabulary: Any/All for existence checks, First/FirstOrDefault/Single/SingleOrDefault for extracting one element (each with different failure semantics), Take/Skip for paging, Distinct for de-duplication, Join and GroupJoin for relational-style combining of two sequences, and Aggregate for custom reductions. Choosing First vs Single matters: First simply returns the first match (or throws/returns default if none), while Single asserts exactly one match exists and throws if there are zero or more than one — a useful invariant check when 'more than one' would indicate a data bug.

🏏

Cricket analogy: Any checks 'did anyone score a century' while All checks 'did everyone reach fifty'; First just grabs the top scorer even with ties, but Single insists there's exactly one century-maker and throws if two batsmen both hit one - useful when only one award should exist.

LINQ to Objects (over IEnumerable<T>) executes entirely in memory using compiled delegates. LINQ to Entities/SQL (over IQueryable<T>), used by EF Core, instead builds an expression tree that is translated into SQL and executed on the database — the same Where/Select syntax produces very different execution depending on which interface the source implements.

Calling a LINQ query multiple times (e.g., in a loop, or passing it to both Count() and foreach) re-executes the whole pipeline each time because of deferred execution. Against a database or slow source this can mean duplicate queries or duplicate side effects; materialize with ToList()/ToArray() once you need to reuse results.

  • LINQ provides a unified, declarative way to query in-memory collections (IEnumerable<T>) and remote data sources (IQueryable<T>) with the same operator vocabulary.
  • Method syntax and query syntax are interchangeable; method syntax compiles the same way and is generally preferred for composability.
  • Most LINQ operators use deferred execution — the query only runs when enumerated, not when declared.
  • First/FirstOrDefault tolerate multiple or zero matches differently than Single/SingleOrDefault, which enforce exactly-one semantics.
  • GroupBy, Join, and Aggregate cover relational-style grouping, combining, and custom reductions without manual loops.
  • IQueryable<T> sources like EF Core translate LINQ expression trees into SQL, so not all C# code inside a query is guaranteed to be translatable.

Practice what you learned

Was this page helpful?

Topics covered

#CStudyNotes#Programming#LINQBasics#LINQ#Deferred#Execution#Streaming#StudyNotes#SkillVeris#ExamPrep