Lesson 21 — Language Integrated Query
LINQ
LINQ is one of C#'s most powerful features — composable, readable queries over collections, databases, and any IEnumerable source without writing loops.
CSHARP — LINQ method syntax
using System.Linq;
int[] marks = { 45, 72, 80, 58, 91, 66, 55, 38 };
// Filtering:
var passing = marks.Where(m => m >= 50).ToList();
Console.WriteLine($"Passing: {string.Join(", ", passing)}");
// Projection (transform each element):
var labels = marks.Select(m => m >= 50 ? "Pass" : "Fail").ToList();
// Aggregation:
Console.WriteLine($"Average: {marks.Average():F1}");
Console.WriteLine($"Max: {marks.Max()}");
Console.WriteLine($"Count >= 70: {marks.Count(m => m >= 70)}");
// Sorting:
var top3 = marks.OrderByDescending(m => m).Take(3).ToList();
Console.WriteLine($"Top 3: {string.Join(", ", top3)}");
LINQ on Objects
CSHARP — LINQ on objects
var learners = new List<Learner> { /* ... */ };
// Chain operations:
var results = learners
.Where(l => l.Mark >= 50) // filter
.OrderByDescending(l => l.Mark) // sort
.ThenBy(l => l.Name) // secondary sort
.Select(l => new { // project to anonymous type
l.Name,
l.Course,
Grade = l.Mark >= 80 ? "Distinction"
: l.Mark >= 60 ? "Merit" : "Pass"
})
.ToList();
foreach (var r in results)
Console.WriteLine($"{r.Name,-15} {r.Course,-10} {r.Grade}");
// Grouping:
var byCourse = learners
.GroupBy(l => l.Course)
.Select(g => new { Course = g.Key, Count = g.Count(), Avg = g.Average(l => l.Mark) });
foreach (var g in byCourse)
Console.WriteLine($"{g.Course}: {g.Count} learners, avg {g.Avg:F1}%");
Practice Task
Your Turn
Given a List of learners with Name, Course, Mark: (1) find all with mark >= 60 sorted by mark descending, (2) calculate average per course using GroupBy, (3) find the top learner overall, (4) create a Dictionary mapping name to grade label using ToDictionary. Print all results.
Common Mistakes
- Forgetting using System.Linq;
- Multiple enumeration without ToList() — lazy evaluation means the query runs every time you enumerate.
- LINQ in a loop that calls the database — use ToList() to materialise first.
- Overly complex LINQ chains — sometimes a foreach loop is clearer.
Professional Tip
LINQ is lazy — the query is not executed until you enumerate it (foreach, ToList, Count, etc.). This is powerful but means calling ToList() at the right moment matters for performance.
Mini Quiz
What does .Where(m => m >= 50) do in LINQ?
Where filters — it returns a new sequence containing only elements satisfying the predicate. It is lazy — no work happens until enumerated.