C# - LINQ
LINQ (Language Integrated Query) in C# provides a way to query data from different sources (such as arrays, collections, databases) using a unified syntax. LINQ allows you to write queries directly in C# without needing to use SQL or other query languages. It integrates query capabilities into the C# language, making data manipulation more intuitive and expressive.
Here’s an overview of LINQ, including syntax, common operations, and examples:
1. LINQ Query Syntax
LINQ queries are written using a declarative syntax similar to SQL. They can be used to query arrays, collections, databases, XML, and more.
Basic Query Syntax
csharpvar query = from item in collection
where condition
select item;
2. LINQ to Objects
LINQ to Objects queries data from in-memory collections like arrays, lists, and dictionaries.
Example with Arrays
csharpusing System;
using System.Linq;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3, 4, 5, 6 };
// Query syntax
var evenNumbers = from number in numbers
where number % 2 == 0
select number;
// Method syntax
var oddNumbers = numbers.Where(n => n % 2 != 0);
Console.WriteLine("Even Numbers:");
foreach (var number in evenNumbers)
{
Console.WriteLine(number);
}
Console.WriteLine("Odd Numbers:");
foreach (var number in oddNumbers)
{
Console.WriteLine(number);
}
}
}
3. LINQ to Collections
LINQ can be used with various collections such as List<T>
, Dictionary<TKey, TValue>
, and HashSet<T>
.
Example with List<T>
csharpusing System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<string> names = new List<string> { "Alice", "Bob", "Charlie", "David" };
// Query syntax
var longNames = from name in names
where name.Length > 4
select name;
// Method syntax
var shortNames = names.Where(n => n.Length <= 4);
Console.WriteLine("Names with more than 4 characters:");
foreach (var name in longNames)
{
Console.WriteLine(name);
}
Console.WriteLine("Names with 4 or fewer characters:");
foreach (var name in shortNames)
{
Console.WriteLine(name);
}
}
}
4. LINQ to SQL/Entity Framework
LINQ can also be used to query databases when using Object-Relational Mapping (ORM) tools like Entity Framework.
Example with Entity Framework
csharpusing System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
public class ApplicationContext : DbContext
{
public DbSet<Person> People { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main()
{
using (var context = new ApplicationContext())
{
var adults = from person in context.People
where person.Age >= 18
select person;
foreach (var person in adults)
{
Console.WriteLine($"{person.Name}, {person.Age} years old");
}
}
}
}
5. Common LINQ Operations
Select
- Projects each element of a sequence into a new form.
csharpvar names = new List<string> { "Alice", "Bob", "Charlie" };
var nameLengths = names.Select(name => name.Length);
Where
- Filters a sequence of values based on a predicate.
csharpvar numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0);
OrderBy
and OrderByDescending
- Sorts a sequence in ascending or descending order.
csharpvar sortedNumbers = numbers.OrderBy(n => n);
var reverseSortedNumbers = numbers.OrderByDescending(n => n);
GroupBy
- Groups the elements of a sequence by a specified key.
csharpvar people = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Charlie", Age = 25 }
};
var groupedByAge = people.GroupBy(p => p.Age);
foreach (var group in groupedByAge)
{
Console.WriteLine($"Age: {group.Key}");
foreach (var person in group)
{
Console.WriteLine($" {person.Name}");
}
}
Join
- Joins two sequences based on a key.
csharpvar students = new List<Student>
{
new Student { Id = 1, Name = "Alice" },
new Student { Id = 2, Name = "Bob" }
};
var grades = new List<Grade>
{
new Grade { StudentId = 1, Course = "Math", GradeValue = "A" },
new Grade { StudentId = 2, Course = "English", GradeValue = "B" }
};
var studentGrades = from student in students
join grade in grades on student.Id equals grade.StudentId
select new { student.Name, grade.Course, grade.GradeValue };
foreach (var item in studentGrades)
{
Console.WriteLine($"{item.Name} - {item.Course}: {item.GradeValue}");
}
Aggregate
- Applies an accumulator function over a sequence.
csharpvar numbers = new List<int> { 1, 2, 3, 4, 5 };
var sum = numbers.Aggregate((total, next) => total + next);
6. Deferred vs. Immediate Execution
Deferred Execution: LINQ queries are not executed when they are defined but rather when they are iterated over. This allows for optimization and composition of queries.
Immediate Execution: Methods like
ToList()
,ToArray()
, andCount()
force immediate execution of the query.
Example of Deferred Execution
csharpvar numbers = Enumerable.Range(1, 10).Where(n => n % 2 == 0);
Console.WriteLine(numbers.Count()); // Query executes here
Summary
LINQ is a powerful feature of C# that provides a unified way to query various data sources. It allows for expressive and readable code through both query and method syntax. LINQ operations include filtering, projection, sorting, grouping, joining, and aggregation. Whether working with in-memory collections or querying databases with Entity Framework, LINQ can greatly enhance productivity and maintainability in your C# applications.