Skip to main content

.NET LINQ Introduction

What is LINQ?

LINQ (Language Integrated Query) is one of the most powerful features in the .NET framework. Added in .NET 3.5 and C# 3.0, LINQ provides a consistent, expressive, and efficient way to query and manipulate data from various data sources, such as collections, databases, XML, and more.

Think of LINQ as SQL queries integrated directly into your C# code, but with more capabilities and flexibility.

Why Learn LINQ?

Before diving deeper, you might wonder why LINQ is worth learning:

  • Unified syntax: Query any data source with the same syntax
  • Type safety: Compile-time checking helps avoid runtime errors
  • Readability: Expressive syntax makes code intentions clear
  • Productivity: Write less code to accomplish complex data operations
  • Flexibility: Works with in-memory collections, databases, XML, and more

LINQ Basics

LINQ provides two syntax options to write queries:

  1. Query Syntax: Similar to SQL, declarative and readable
  2. Method Syntax: Uses extension methods, often more flexible

Let's look at both with a simple example - filtering a list of numbers to find even values:

Query Syntax Example

csharp
// Create a list of numbers
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Query syntax to find even numbers
var evenNumbers = from num in numbers
where num % 2 == 0
select num;

// Display results
Console.WriteLine("Even numbers:");
foreach (int num in evenNumbers)
{
Console.WriteLine(num);
}

Output:

Even numbers:
2
4
6
8
10

Method Syntax Example

The same operation using method syntax:

csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Method syntax to find even numbers
var evenNumbers = numbers.Where(num => num % 2 == 0);

Console.WriteLine("Even numbers:");
foreach (int num in evenNumbers)
{
Console.WriteLine(num);
}

The output is identical, but the approach is different. Method syntax often appears more concise and is generally preferred by experienced developers, though query syntax can be more readable for complex queries.

Key LINQ Concepts

1. Deferred Execution

An important concept in LINQ is that most LINQ queries don't execute immediately when defined. Instead, they execute when the result is actually needed (like in a foreach loop). This is called deferred execution.

csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// This query is defined but not executed yet
var query = numbers.Where(n => n > 2);

// Adding a new number to the source collection
numbers.Add(6);

// Now the query executes, including the newly added number
foreach (int n in query)
{
Console.WriteLine(n);
}

Output:

3
4
5
6

Notice that the query included the value 6 even though it was added after the query was defined. This demonstrates deferred execution.

2. Query Operators

LINQ comes with numerous operators that perform various tasks on collections:

  • Filtering: Where, Take, Skip, TakeWhile, SkipWhile
  • Sorting: OrderBy, OrderByDescending, ThenBy, ThenByDescending, Reverse
  • Grouping: GroupBy
  • Joining: Join, GroupJoin
  • Projection: Select, SelectMany
  • Aggregation: Count, Sum, Min, Max, Average
  • Quantifiers: Any, All, Contains
  • Element Operations: First, FirstOrDefault, Single, SingleOrDefault, etc.

Here's a simple example using multiple operators:

csharp
List<int> numbers = new List<int> { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

// Chain multiple operations - filter, sort, and take
var result = numbers
.Where(n => n > 3) // Filter numbers greater than 3
.OrderBy(n => n) // Sort in ascending order
.Take(3); // Take only first 3 results

Console.WriteLine("First 3 numbers greater than 3 (sorted):");
foreach (int n in result)
{
Console.WriteLine(n);
}

Output:

First 3 numbers greater than 3 (sorted):
4
5
6

Practical Example: Working with Objects

LINQ truly shines when working with collections of objects. Here's a practical example using a Product class:

csharp
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
}

// Creating a list of products
List<Product> products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Category = "Electronics", Price = 999.99m, StockQuantity = 10 },
new Product { Id = 2, Name = "Smartphone", Category = "Electronics", Price = 699.99m, StockQuantity = 15 },
new Product { Id = 3, Name = "Headphones", Category = "Electronics", Price = 149.99m, StockQuantity = 20 },
new Product { Id = 4, Name = "Desk Chair", Category = "Furniture", Price = 249.99m, StockQuantity = 5 },
new Product { Id = 5, Name = "Coffee Table", Category = "Furniture", Price = 199.99m, StockQuantity = 3 },
new Product { Id = 6, Name = "T-shirt", Category = "Clothing", Price = 19.99m, StockQuantity = 50 },
new Product { Id = 7, Name = "Jeans", Category = "Clothing", Price = 49.99m, StockQuantity = 30 },
};

// Find all electronics that cost less than 200 and are in stock
var affordableElectronics = products
.Where(p => p.Category == "Electronics" && p.Price < 200 && p.StockQuantity > 0)
.OrderBy(p => p.Price);

// Display results
Console.WriteLine("Affordable Electronics:");
foreach (var product in affordableElectronics)
{
Console.WriteLine($"{product.Name} - ${product.Price} ({product.StockQuantity} in stock)");
}

// Group products by category and calculate total value per category
var categoryValues = products
.GroupBy(p => p.Category)
.Select(g => new {
Category = g.Key,
TotalItems = g.Count(),
TotalValue = g.Sum(p => p.Price * p.StockQuantity)
})
.OrderByDescending(x => x.TotalValue);

// Display results
Console.WriteLine("\nInventory Value by Category:");
foreach (var category in categoryValues)
{
Console.WriteLine($"{category.Category}: {category.TotalItems} items, total value: ${category.TotalValue}");
}

Output:

Affordable Electronics:
Headphones - $149.99 (20 in stock)

Inventory Value by Category:
Electronics: 3 items, total value: $20499.7
Clothing: 2 items, total value: $2499.5
Furniture: 2 items, total value: $1850.0

Common Use Cases for LINQ

LINQ is incredibly versatile. Here are some common scenarios where LINQ excels:

  1. Data filtering and sorting: Apply complex conditions to filter collections and sort results
  2. Data transformation: Convert one data structure to another with mapping operations
  3. Data aggregation: Compute statistics like sums, averages, minimums, and maximums
  4. Joining data: Combine data from multiple sources based on related properties
  5. Paging data: Implement data pagination for UI display (using Skip and Take)

LINQ and Collections

LINQ works with any collection that implements the IEnumerable<T> interface, which includes:

  • Arrays
  • Lists, Sets, Queues, Stacks
  • Dictionaries (though LINQ operates on key-value pairs)
  • Custom collections

Let's see LINQ with different collection types:

csharp
// Array
string[] names = { "Alice", "Bob", "Charlie", "David", "Eve" };
var namesWithA = names.Where(name => name.Contains('a') || name.Contains('A'));

// List
List<double> prices = new List<double> { 10.5, 20.99, 5.75, 15.25, 3.99 };
var averagePrice = prices.Average();

// Dictionary
Dictionary<string, int> ages = new Dictionary<string, int>
{
{ "Alice", 25 },
{ "Bob", 30 },
{ "Charlie", 35 },
{ "David", 40 }
};
var adults = ages.Where(pair => pair.Value >= 30)
.Select(pair => pair.Key);

// Display results
Console.WriteLine("Names containing 'a':");
foreach (var name in namesWithA)
{
Console.WriteLine(name);
}

Console.WriteLine($"\nAverage price: ${averagePrice}");

Console.WriteLine("\nPeople aged 30 or older:");
foreach (var person in adults)
{
Console.WriteLine(person);
}

Output:

Names containing 'a':
Alice
Charlie
David

Average price: $11.296

People aged 30 or older:
Bob
Charlie
David

Summary

In this introduction to LINQ, we've covered:

  • What LINQ is and why it's valuable
  • The two LINQ syntax options: query syntax and method syntax
  • Key LINQ concepts including deferred execution
  • Common LINQ operators for various data operations
  • Working with objects and different collection types using LINQ

LINQ is a powerful tool that can significantly improve your code's readability and efficiency when working with data. As you become more comfortable with LINQ, you'll find it indispensable for many programming tasks.

Additional Resources and Exercises

Resources

Practice Exercises

  1. Basic Filtering: Create a list of integers and write a LINQ query to find all numbers divisible by both 3 and 5.

  2. Working with Objects: Create a Student class with properties for Name, Age, and Grade. Create a collection of students and use LINQ to:

    • Find all students with a grade above 80
    • Find the average age of students with passing grades (above 60)
    • Group students by grade ranges (0-59, 60-79, 80-100)
  3. Multiple Data Sources: Create two lists - one of authors and one of books (with an AuthorId property). Use LINQ's Join operation to match books with their authors.

  4. Complex Querying: Given a list of orders with customer information, order date, and order items, write LINQ queries to:

    • Find the top 3 customers by total purchase amount
    • Calculate monthly sales for the past year
    • Identify the most popular product (most frequently purchased)

By practicing these exercises, you'll gain confidence in using LINQ for real-world data manipulation tasks!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)