LINQ  

Mastering LINQ in C#

Introduction

Language Integrated Query (LINQ) is a game-changer in C#. It brings SQL-like data querying capabilities directly into your C# code, making data manipulation more intuitive, type-safe, and readable.

In this article, you’ll learn,

  • What LINQ is and why it’s useful
  • The different types of LINQ
  • Query Syntax vs Method Syntax
  • Common and advanced LINQ methods (including Zip, Chunk, OfType, and SelectMany)
  • Practical examples for each method

What is LINQ in C#?

LINQ (Language Integrated Query) is a powerful feature that lets you query data directly in C# using a clear, readable syntax.

With LINQ, you can query.

  • Collections in memory (arrays, lists)
  • Databases (via Entity Framework or LINQ to SQL)
  • XML files
  • Datasets
  • Custom collections

This unifies how you interact with data; you write queries in C#, not SQL or XQuery.

Types of LINQ

LINQ Type Purpose
LINQ to Objects Query in-memory collections like arrays and lists
LINQ to SQL Query SQL Server databases
LINQ to Entities Query databases using Entity Framework
LINQ to XML Query and manipulate XML data
LINQ to DataSet Query DataSets and DataTables in ADO.NET

Query Syntax vs Method Syntax

LINQ offers two ways to write queries.

1. Query Syntax

Similar to SQL, it's best for simple queries.

var evenNumbers = from n in numbers
                  where n % 2 == 0
                  select n;

2. Method Syntax

Uses extension methods with lambdas, more flexible for complex queries.

var evenNumbers = numbers.Where(n => n % 2 == 0);

Both produce the same result; use what fits your style!

Essential LINQ Methods

Let’s break down the most commonly used LINQ methods, with clear explanations and examples.

1. Where

Filters elements by a condition.

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

2. Select

Projects each element to a new form.

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

3. OrderBy / OrderByDescending

Sorts elements.

var sorted = people.OrderBy(p => p.Name);
var sortedDesc = people.OrderByDescending(p => p.Age);

4. ThenBy / ThenByDescending

For secondary sorting.

var sorted = people.OrderBy(p => p.LastName).ThenBy(p => p.FirstName);

5. GroupBy

Group elements by a key.

var grouped = people.GroupBy(p => p.Age);
foreach (var group in grouped)
{
    Console.WriteLine($"Age: {group.Key}");
    foreach (var p in group) Console.WriteLine($" - {p.Name}");
}

6. Join

Joins two collections based on matching keys.

var result = customers.Join(
    orders,
    c => c.Id,
    o => o.CustomerId,
    (c, o) => new { c.Name, o.OrderId }
);

7. Distinct

Removes duplicates.

var uniqueAges = people.Select(p => p.Age).Distinct();

8. Union, Intersect, Except

Set operations.

var combined = list1.Union(list2);
var common = list1.Intersect(list2);
var difference = list1.Except(list2);

9. Any / All

Check for matches.

bool hasAdults = people.Any(p => p.Age >= 18);
bool allAdults = people.All(p => p.Age >= 18);

10. First / FirstOrDefault / Single / SingleOrDefault

Fetch single elements.

var firstAdult = people.First(p => p.Age >= 18);
var maybeAdult = people.FirstOrDefault(p => p.Age >= 18);

11. Take / Skip

Useful for paging.

var page = people.Skip(10).Take(10);

Advanced LINQ Methods: Let’s cover some lesser-known but powerful LINQ methods.

12. Zip

Combines two sequences element-wise.

int[] numbers = { 1, 2, 3 };
string[] words = { "one", "two", "three" };

var zipped = numbers.Zip(words, (n, w) => $"{n} = {w}");

foreach (var item in zipped)
{
    Console.WriteLine(item);
}
// Output:
// 1 = one
// 2 = two
// 3 = three

13. Chunk

Splits a sequence into chunks of a specified size. (.NET 6+)

int[] nums = { 1, 2, 3, 4, 5, 6, 7 };

var chunks = nums.Chunk(3);

foreach (var chunk in chunks)
{
    Console.WriteLine(string.Join(", ", chunk));
}
// Output:
// 1, 2, 3
// 4, 5, 6
// 7

14. OfType

Filters by type, useful for mixed collections.

object[] mixed = { "hello", 42, "world", 100 };

var strings = mixed.OfType<string>();

foreach (var s in strings)
{
    Console.WriteLine(s);
}
// Output:
// hello
// world

15. SelectMany

Projects collections within collections and flattens them.

var students = new[]
{
    new { Name = "Alice", Subjects = new[] { "Math", "Science" } },
    new { Name = "Bob", Subjects = new[] { "English", "History" } }
};

var allSubjects = students.SelectMany(s => s.Subjects);

foreach (var subject in allSubjects)
{
    Console.WriteLine(subject);
}
// Output:
// Math
// Science
// English
// History

Complete Example

var people = new[]
{
    new { Name = "Alice", Age = 25, Hobbies = new[] { "Reading", "Hiking" } },
    new { Name = "Bob", Age = 30, Hobbies = new[] { "Gaming", "Cycling" } },
    new { Name = "Charlie", Age = 25, Hobbies = new[] { "Swimming" } }
};

// Select names of people over 20, ordered by name, group by age.
var query = people
    .Where(p => p.Age > 20)
    .OrderBy(p => p.Name)
    .GroupBy(p => p.Age);

foreach (var group in query)
{
    Console.WriteLine($"Age: {group.Key}");
    foreach (var p in group)
        Console.WriteLine($" - {p.Name}");
}

// Use SelectMany to flatten hobbies.
var allHobbies = people.SelectMany(p => p.Hobbies).Distinct();

Console.WriteLine("All hobbies: " + string.Join(", ", allHobbies));

Key Takeaways

  • LINQ makes querying data in C# clear and concise.
  • You can use Query or Method syntax.
  • Mastering methods like Zip, Chunk, OfType, and SelectMany will make your code more powerful and expressive.
  • LINQ works with collections, SQL, XML, and more — one consistent approach for all.

Conclusion

Language Integrated Query (LINQ) is more than just syntactic sugar in C# — it’s a robust querying framework that unifies the way developers access and transform data. Whether you're working with in-memory objects, databases, XML, or mixed data sources, LINQ provides a consistent, expressive, and readable way to write queries.

In this article, we explored both the foundational and advanced LINQ methods, including essentials like Where, Select, and GroupBy, as well as powerful operators such as Zip, Chunk, OfType, and SelectMany. Each method serves a unique purpose, helping developers write cleaner, safer, and more maintainable code.