本文仅作为参考大佬们文章的总结。
LINQ(Language Integrated Query,语言集成查询)是C#中一项革命性的技术,它将查询功能直接集成到C#语言中,使开发者能够以声明式的方式查询各种数据源。LINQ提供了一种统一的语法来查询和操作不同类型的数据,包括内存中的集合、数据库、XML文档等,极大地简化了数据处理流程。
LINQ是.NET Framework 3.5引入的一项技术,它允许开发者使用类似SQL的语法来查询各种数据源。LINQ的主要价值在于:
统一查询模型:提供一致的语法查询不同类型的数据源(集合、数据库、XML等)
类型安全:编译时检查查询的正确性,减少运行时错误
提高生产力:减少样板代码,使查询逻辑更加直观和简洁
语言集成:直接使用C#语法编写查询,无需学习特定领域语言(如SQL、XPath等)
LINQ由多个组件组成,针对不同数据源提供支持:
LINQ to Objects:查询内存中的集合和数组
LINQ to SQL:查询SQL Server数据库(已逐渐被Entity Framework取代)
LINQ to Entities:通过Entity Framework查询各种数据库
LINQ to XML:查询和操作XML文档
LINQ to DataSet:查询DataSet对象
并行LINQ(PLINQ):提供并行查询功能,提高大数据集处理性能
查询表达式语法类似于SQL,使用关键字如from
、where
、select
等构建查询:
// 查询语法示例:从数字集合中找出大于80的数字
int[] scores = { 97, 92, 81, 60 };
IEnumerable scoreQuery =
from score in scores
where score > 80
select score;
方法语法使用扩展方法和Lambda表达式构建查询,更接近函数式编程风格:
// 方法语法示例:与上面查询语法等效
int[] scores = { 97, 92, 81, 60 };
IEnumerable scoreQuery = scores.Where(score => score > 80);
方法语法通常更简洁,特别是在链式调用多个操作时。
特性 |
查询表达式语法 |
方法语法 |
---|---|---|
可读性 |
类似SQL,更直观 |
需要熟悉Lambda表达式 |
灵活性 |
适合简单查询 |
适合复杂查询和链式调用 |
编译转换 |
编译为方法调用 |
直接使用方法调用 |
适用场景 |
简单过滤、投影 |
复杂操作、自定义扩展 |
实际上,编译器会将查询表达式语法转换为方法语法,两者在性能和功能上没有区别。
Where:基于谓词筛选元素
var evenNumbers = numbers.Where(n => n % 2 == 0);
OfType:筛选指定类型的元素
var strings = collection.OfType();
Select:将元素投影为新形式
var squares = numbers.Select(n => n * n);
SelectMany:展平嵌套集合
var allOrders = customers.SelectMany(c => c.Orders);
OrderBy/OrderByDescending:主排序(升序/降序)
var sortedProducts = products.OrderBy(p => p.Price);
ThenBy/ThenByDescending:次级排序
var sorted = products.OrderBy(p => p.Category)
.ThenByDescending(p => p.Price);
GroupBy:按键分组元素
var groups = products.GroupBy(p => p.Category);
ToLookup:创建不可变查找表
var lookup = products.ToLookup(p => p.Category);
Join:内连接两个序列
var joined = from c in customers
join o in orders on c.ID equals o.CustomerID
select new { c.Name, o.Product };
GroupJoin:分组连接(左外连接)
var groupJoined = from d in departments
join e in employees on d.ID equals e.DeptID into emps
select new { Department = d, Employees = emps };
Count:计数
int count = products.Count();
Sum/Average:求和/平均值
decimal total = products.Sum(p => p.Price);
double avg = products.Average(p => p.Price);
Min/Max:最小值/最大值
decimal minPrice = products.Min(p => p.Price);
Aggregate:自定义聚合
int product = numbers.Aggregate((acc, n) => acc * n);
大多数LINQ操作符(如Where、Select、OrderBy等)采用延迟执行策略,查询定义时不会立即执行,只有在实际枚举结果(如foreach循环、调用ToList()等)时才会执行。
延迟执行示例:
var query = products.Where(p => p.Price > 100); // 查询未执行
products.Add(new Product { Price = 200 }); // 修改数据源
foreach (var p in query) // 查询在此处执行
{
Console.WriteLine(p.Name); // 包含新添加的产品
}
延迟执行的优点是可以优化性能,避免不必要的计算,特别是在处理大数据集时。
某些操作会强制查询立即执行并缓存结果,包括:
转换操作:ToList()、ToArray()、ToDictionary()
聚合操作:Count()、Sum()、Average()、Min()、Max()
元素操作:First()、Last()、Single()
立即执行示例:
var expensiveProducts = products
.Where(p => p.Price > 100)
.ToList(); // 查询立即执行并转换为列表
即执行适用于需要立即获取结果或多次使用同一结果的场景。
LINQ特别适合查询复杂对象集合,例如学生管理系统:
class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Score { get; set; }
}
List students = new List
{
new Student { Id = 1, Name = "张三", Score = 85 },
new Student { Id = 2, Name = "李四", Score = 92 },
new Student { Id = 3, Name = "王五", Score = 78 }
};
// 查询分数≥90的学生并按姓名降序排列
var topStudents = from s in students
where s.Score >= 90
orderby s.Name descending
select s;
使用GroupBy进行复杂分组分析:
// 按分数段分组(每10分为一段)
var grouped = from s in students
group s by s.Score / 10 into g
orderby g.Key descending
select new
{
Grade = g.Key * 10,
Count = g.Count(),
Students = g
};
结合Join操作关联不同数据源:
class Order
{
public int Id { get; set; }
public int StudentId { get; set; }
public decimal Amount { get; set; }
}
List orders = new List
{
new Order { Id = 1, StudentId = 1, Amount = 100 },
new Order { Id = 2, StudentId = 2, Amount = 200 }
};
// 学生与订单内连接
var query = from s in students
join o in orders on s.Id equals o.StudentId
select new { s.Name, o.Amount };
合理使用延迟执行:避免在循环中重复执行相同查询,可缓存结果
选择合适的数据结构:对于频繁查询的集合,考虑使用Dictionary或HashSet
分批处理大数据集:使用Skip/Take实现分页查询
避免过度嵌套:复杂查询可拆分为多个步骤,提高可读性
数据库查询优化:对于LINQ to SQL/Entities,注意生成的SQL语句效率
代码简洁:减少样板代码,查询逻辑更加直观
类型安全:编译时检查,减少运行时错误
统一查询模型:相同语法查询不同数据源
提高开发效率:减少上下文切换(如C#/SQL切换)
强大的表达能力:支持复杂查询、转换和分析操作
性能开销:某些复杂查询可能不如手写SQL或特定API高效
调试困难:复杂查询的调试可能比较困难
黑盒效应:特别是数据库查询,开发者可能不了解生成的SQL
// 从产品列表中获取最贵的3个电子产品
var top3ElectronicProducts = products
.Where(p => p.Category == "Electronics")
.OrderByDescending(p => p.Price)
.Take(3)
.ToList();
using (var context = new MyDbContext())
{
// 查询年龄大于18岁的用户
var adultUsers = from u in context.Users
where u.Age > 18
select u;
var userList = adultUsers.ToList(); // 触发SQL执行
}
XDocument doc = XDocument.Load("Employees.xml");
var highSalaryEmployees = from e in doc.Descendants("Employee")
where (decimal)e.Element("Salary") > 5000
select new
{
Name = e.Element("Name").Value,
Salary = e.Element("Salary").Value
};