
Learn C# LINQ with 5 practical examples you'll use every day. Master Where, Select, GroupBy, OrderBy, and aggregation with runnable code. Start coding now!
C# LINQ (Language Integrated Query) is one of the most powerful features in the .NET ecosystem, and learning it well will instantly make you a more productive developer. If you've ever written nested for loops just to filter a list, group some records, or calculate a total, this C# LINQ tutorial will change how you write code forever. In this guide, you'll learn LINQ through 5 practical examples a developer would actually use every single day, complete with runnable code and an explanation of why each approach works.
LINQ lets you query collections, databases, XML, and more using a clean, readable, SQL-like syntax directly in C#. Instead of describing how to loop through data step by step, you describe what you want, and the compiler handles the rest. Let's dive into the most useful LINQ examples you'll reach for constantly.
What Is C# LINQ and Why Should You Use It?
LINQ is a set of extension methods (living in the System.Linq namespace) that let you query any object implementing IEnumerable<T>. The biggest benefit of C# LINQ is readability: a single expressive line can replace a dozen lines of imperative loop code. This means fewer bugs, less boilerplate, and code that reads like the problem you're solving.
There are two syntaxes you'll encounter:
- Method syntax (fluent):
list.Where(x => x > 5)— the most common in real codebases. - Query syntax:
from x in list where x > 5 select x— reads like SQL.
Both compile to the exact same thing. This tutorial focuses on method syntax because it's what you'll see in 90% of professional .NET projects. Make sure you add this at the top of your file:
using System;
using System.Collections.Generic;
using System.Linq;
For all examples below, we'll use a simple Product model and a sample list:
public record Product(int Id, string Name, string Category, decimal Price, int Stock);
var products = new List<Product>
{
new(1, "Laptop", "Electronics", 1200m, 5),
new(2, "Mouse", "Electronics", 25m, 40),
new(3, "Desk", "Furniture", 300m, 0),
new(4, "Chair", "Furniture", 150m, 12),
new(5, "Monitor", "Electronics", 400m, 8),
new(6, "Notebook", "Stationery", 3m, 200)
};
Example 1: Filtering Data with LINQ Where
The most common daily LINQ operation is filtering. The Where method takes a predicate (a function that returns true or false) and returns only the elements that match. This is the bread and butter of LINQ Where Select queries.
// Get all electronics that are in stock
var availableElectronics = products
.Where(p => p.Category == "Electronics" && p.Stock > 0)
.ToList();
foreach (var p in availableElectronics)
Console.WriteLine($"{p.Name} - ${p.Price}");
// Output:
// Laptop - $1200
// Mouse - $25
// Monitor - $400
Why it works: Where uses deferred execution — the query doesn't actually run until you enumerate it (here, with .ToList() or the foreach). This means you can build up complex queries without paying any performance cost until you ask for the results. It also reads almost like plain English, which makes maintenance far easier than a manual loop with an if statement inside.
Example 2: Transforming Data with LINQ Select
The Select method projects each element into a new shape. You'll use this constantly to map domain models to DTOs, extract a single property, or build view models. This is the second half of the famous LINQ Where Select combo.
// Project to a lightweight anonymous object
var summaries = products
.Where(p => p.Price > 100)
.Select(p => new { p.Name, PriceWithTax = p.Price * 1.2m })
.ToList();
foreach (var s in summaries)
Console.WriteLine($"{s.Name}: ${s.PriceWithTax:F2}");
// Output:
// Laptop: $1440.00
// Desk: $360.00
// Chair: $180.00
// Monitor: $480.00
Why it works: Select returns a new sequence without mutating the original list — a core principle of functional, side-effect-free programming. Using an anonymous type (new { ... }) lets you shape exactly the data you need, which is perfect for APIs where you don't want to leak internal fields. Combine Where and Select and you can express filter-then-transform pipelines in a single fluent chain.
Example 3: Sorting Results with OrderBy and ThenBy
Sorting is another everyday task. LINQ's OrderBy, OrderByDescending, and ThenBy make multi-level sorting trivial compared to writing custom comparers.
// Sort by category, then by price (highest first)
var sorted = products
.OrderBy(p => p.Category)
.ThenByDescending(p => p.Price)
.ToList();
foreach (var p in sorted)
Console.WriteLine($"{p.Category,-12} {p.Name,-10} ${p.Price}");
// Output:
// Electronics Laptop $1200
// Electronics Monitor $400
// Electronics Mouse $25
// Furniture Desk $300
// Furniture Chair $150
// Stationery Notebook $3
Why it works: You must use ThenBy (not a second OrderBy) for secondary sorting — chaining OrderBy twice would discard the first sort entirely. OrderBy is also a stable sort, meaning equal elements keep their original relative order, which prevents subtle bugs in UIs and reports.
Example 4: Grouping Data with LINQ GroupBy
When you need to bucket records — sales by region, products by category, users by role — LINQ GroupBy is your go-to. It's one of the most powerful examples in any LINQ tutorial.
// Count products and total inventory value per category
var byCategory = products
.GroupBy(p => p.Category)
.Select(g => new
{
Category = g.Key,
Count = g.Count(),
TotalValue = g.Sum(p => p.Price * p.Stock)
})
.OrderByDescending(x => x.TotalValue)
.ToList();
foreach (var c in byCategory)
Console.WriteLine($"{c.Category}: {c.Count} items, ${c.TotalValue} in stock");
// Output:
// Electronics: 3 items, $10200 in stock
// Furniture: 2 items, $1800 in stock
// Stationery: 1 items, $600 in stock
Why it works: GroupBy returns a sequence of IGrouping<TKey, TElement> objects. Each group exposes a Key (the category here) and is itself enumerable, so you can run aggregates like Count() and Sum() inside the Select. This single query replaces what would otherwise be a dictionary, manual accumulation loops, and a lot of room for error.
Example 5: Aggregating with Sum, Average, and FirstOrDefault
Finally, LINQ shines at calculating totals and finding single records. These aggregation and element operators are used in virtually every business application.
decimal totalInventoryValue = products.Sum(p => p.Price * p.Stock);
decimal averagePrice = products.Average(p => p.Price);
int totalUnits = products.Sum(p => p.Stock);
// Find the first out-of-stock product (or null if none exist)
Product? outOfStock = products.FirstOrDefault(p => p.Stock == 0);
Console.WriteLine($"Total value: ${totalInventoryValue}");
Console.WriteLine($"Average price: ${averagePrice:F2}");
Console.WriteLine($"Out of stock: {outOfStock?.Name ?? \"None\"}");
// Output:
// Total value: $12600
// Average price: $346.33
// Out of stock: Desk
Why it works: Always prefer FirstOrDefault over First when a match might not exist — First throws an InvalidOperationException on an empty result, while FirstOrDefault safely returns null (or the default value). This single habit prevents a huge category of runtime crashes.
LINQ Best Practices and Common Pitfalls
Now that you know how to use LINQ in C# day to day, keep these best practices in mind:
- Beware multiple enumeration. Each time you iterate a deferred query, it re-runs. If you'll use the results more than once, call
.ToList()once and reuse it. - Don't query inside hot loops. Materializing the same LINQ query repeatedly inside a loop can quietly destroy performance. Cache it outside the loop.
- Use
Any()instead ofCount() > 0.Any()stops at the first match, whileCount()walks the entire sequence. - Know the difference between IEnumerable and IQueryable. With Entity Framework,
IQueryabletranslates LINQ to SQL and runs on the database; calling.ToList()too early pulls every row into memory first. - Keep chains readable. If a LINQ query grows past 4–5 operators, break it onto multiple lines or extract a helper method.
Conclusion: Master C# LINQ One Query at a Time
You've now seen the 5 C# LINQ patterns you'll reach for every single day: filtering with Where, transforming with Select, sorting with OrderBy/ThenBy, bucketing with GroupBy, and aggregating with Sum, Average, and FirstOrDefault. Together they cover the vast majority of real-world data manipulation you'll do as a .NET developer.
Key takeaways:
- LINQ replaces verbose loops with clear, declarative queries.
- Deferred execution means queries run only when enumerated — call
.ToList()to materialize results. Where+Selectis the most common combo you'll write.- Prefer safe operators like
FirstOrDefaultandAny()to avoid exceptions and wasted work. - Watch for multiple enumeration and the IEnumerable vs IQueryable distinction in performance-critical code.
The best way to learn LINQ is to use it. Open your editor, paste in the Product list above, and try rewriting one of your existing for loops as a LINQ query. Once it clicks, you'll never go back. Bookmark this LINQ tutorial and keep practicing — and check out our other C# tutorials on csharp-coder.com to keep leveling up your .NET skills.
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.
Comments
Post a Comment