引言
在现代C#开发中,集合和LINQ(Language Integrated Query)是处理数据的核心工具。它们共同构成了.NET平台上最强大、最灵活的数据操作框架。本文将全面介绍C#集合类型体系、LINQ查询技术以及它们的实际应用场景,帮助您掌握高效数据处理的关键技能。
一、C#集合框架概述
1.1 集合类型层次结构
C#集合类型主要分为以下几类:
- 非泛型集合(System.Collections)
- ArrayList, Hashtable, Queue, Stack等
- 已逐渐被泛型集合取代
- 泛型集合(System.Collections.Generic)
- List, Dictionary, Queue, Stack等
- 类型安全且性能更好
- 并发集合(System.Collections.Concurrent)
- ConcurrentBag, ConcurrentDictionary等
- 线程安全的多线程场景集合
- 不可变集合(System.Collections.Immutable)
- ImmutableList, ImmutableDictionary等
- 线程安全且保证数据不变性
1.2 常用集合类型对比
集合类型 | 描述 | 典型用例 |
---|---|---|
List | 动态数组 | 需要索引访问的集合 |
Dictionary | 键值对集合 | 快速键值查找 |
HashSet | 不重复元素集合 | 去重操作/集合运算 |
Queue | 先进先出集合 | 任务队列处理 |
Stack | 后进先出集合 | 撤销操作/递归替代 |
LinkedList | 双向链表 | 频繁插入/删除操作 |
二、核心集合操作
2.1 集合初始化器
// List初始化
var numbers = new List<int> { 1, 2, 3, 4, 5 };
// Dictionary初始化
var capitals = new Dictionary<string, string>
{
["China"] = "Beijing",
["Japan"] = "Tokyo",
["USA"] = "Washington D.C."
};
2.2 常用集合方法
var list = new List<int> { 1, 2, 3, 4, 5 };
// 添加元素
list.Add(6);
list.AddRange(new[] { 7, 8, 9 });
// 删除元素
list.Remove(3); // 按值删除
list.RemoveAt(0); // 按索引删除
// 查找元素
bool contains = list.Contains(5);
int index = list.IndexOf(4);
// 排序和反转
list.Sort();
list.Reverse();
三、LINQ基础
3.1 LINQ查询语法
LINQ提供了两种查询语法:查询表达式和方法语法。
查询表达式语法:
var query = from num in numbers
where num % 2 == 0
orderby num descending
select num * 2;
方法语法:
var query = numbers
.Where(num => num % 2 == 0)
.OrderByDescending(num => num)
.Select(num => num * 2);
3.2 标准查询操作符
操作符 | 描述 | 示例 |
---|---|---|
Where | 过滤 | .Where(x => x > 5) |
Select | 投影 | .Select(x => x.Name) |
OrderBy | 排序 | .OrderBy(x => x.Age) |
GroupBy | 分组 | .GroupBy(x => x.Department) |
Join | 连接 | .Join(inner, outerKey, innerKey, result) |
Aggregate | 聚合 | .Aggregate((sum, x) => sum + x) |
First/FirstOrDefault | 获取第一个 | .First(x => x.Id == 5) |
Any/All | 条件判断 | .Any(x => x.Score > 90) |
四、高级LINQ技术
4.1 延迟执行与立即执行
// 延迟执行 - 查询只在迭代时执行
var deferredQuery = numbers.Where(n => n > 3);
// 立即执行 - 查询立即执行并返回结果
var immediateResult = numbers.Where(n => n > 3).ToList();
4.2 自定义LINQ操作符
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> source)
{
return source.Where(item => item != null);
}
// 使用自定义操作符
var result = list.WhereNotNull();
4.3 PLINQ (并行LINQ)
var parallelQuery = from num in numbers.AsParallel()
where num % 2 == 0
select num * 2;
五、集合与LINQ性能优化
5.1 集合选择策略
- 频繁查找:使用Dictionary或HashSet(O(1)查找)
- 频繁插入/删除:考虑LinkedList或HashSet
- 只读操作:使用Immutable集合或数组
- 多线程环境:选择Concurrent集合或Immutable集合
5.2 LINQ性能技巧
- 使用
Any()
代替Count() > 0
检查非空 - 在循环外缓存LINQ查询结果
- 使用
Select
和Where
的顺序影响性能 - 考虑使用
AsParallel()
处理大数据集 - 对EF Core等ORM使用
IQueryable
保持查询在数据库执行
六、实际应用示例
6.1 数据转换
var employees = new List<Employee>();
// 转换为DTO列表
var employeeDtos = employees
.Select(e => new EmployeeDto
{
Id = e.Id,
FullName = $"{e.FirstName} {e.LastName}",
Department = e.Department.Name
})
.ToList();
6.2 分组统计
var salesByCategory = products
.GroupBy(p => p.Category)
.Select(g => new
{
Category = g.Key,
TotalSales = g.Sum(p => p.Price * p.Quantity),
AveragePrice = g.Average(p => p.Price)
});
6.3 多数据源关联
var customerOrders = customers
.Join(orders,
customer => customer.Id,
order => order.CustomerId,
(customer, order) => new
{
CustomerName = customer.Name,
OrderDate = order.Date,
Amount = order.TotalAmount
});
七、最佳实践与常见陷阱
7.1 最佳实践
- 优先选择泛型集合而非非泛型集合
- 根据场景选择合适的集合类型
- 对LINQ查询进行合理分解以提高可读性
- 注意
IEnumerable
和IQueryable
的区别 - 为复杂查询编写单元测试
7.2 常见陷阱
- 多次枚举:重复迭代同一IEnumerable导致重复计算
- N+1查询问题:在循环中执行数据库查询
- 内存泄漏:持有大数据集的引用导致GC无法回收
- 过早物化:过早调用
ToList()
/ToArray()
导致性能下降 - 忽略空集合:对可能为空的集合进行操作时未做检查
结语
C#集合框架与LINQ查询的组合为数据处理提供了强大而优雅的解决方案。通过合理选择集合类型、掌握LINQ查询技术并遵循性能优化原则,您可以编写出既简洁又高效的代码。随着经验的积累,您将能够更加灵活地运用这些工具解决各种复杂的数据处理问题。
记住,高效的数据处理不仅关乎代码性能,也关乎代码的可读性和可维护性。希望本指南能帮助您在C#开发中更好地利用集合和LINQ的强大功能。