C# 集合(Collection)(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在 C# 编程中,集合(Collection) 是处理数据存储和操作的核心工具。无论是管理用户信息、商品列表,还是实现复杂的数据结构,集合都提供了灵活且高效的方式。对于初学者而言,理解集合的类型、特性和使用场景,是迈向高级编程的重要一步。本文将从基础概念出发,结合实际案例和代码示例,深入解析 C# 集合的核心知识点,帮助读者构建扎实的实践能力。


一、集合的基础概念与核心特性

1.1 什么是集合?

集合(Collection)可以理解为**“数据的容器”**,它允许开发者将多个元素(如整数、字符串、对象等)组织成一个整体,方便统一管理。例如,一个班级的学生名单可以视为一个字符串集合,而购物车中的商品列表则是一个对象集合。

集合的核心特性包括:

  • 动态扩展性:大多数集合类型(如 List<T>)支持根据需要动态增加或减少元素。
  • 类型安全性:通过泛型(如 List<int>)确保集合中只能存储指定类型的元素。
  • 高效操作:不同集合类型针对特定场景优化了性能,例如快速查找、插入或删除操作。

比喻
集合就像一个智能文件柜,每个抽屉(元素)都有明确的位置(索引或键),而柜子本身可以根据需求扩展大小,甚至支持快速检索特定抽屉的内容。


1.2 集合与数组的区别

在 C# 中,数组(Array)和集合(如 List<T>)都是存储元素的容器,但它们存在关键差异:

特性数组(Array)集合(如 List
大小固定性创建后长度不可变动态扩展,自动调整容量
类型安全性非泛型数组(如 object[])不安全泛型集合(如 List<int>)类型安全
插入/删除效率中间位置操作效率低支持高效插入和删除(部分类型)
内存占用预分配内存,可能浪费空间按需分配,更灵活

案例

// 数组示例  
int[] fixedArray = new int[3]; // 固定长度为3  
fixedArray[0] = 10; // 直接通过索引访问  

// 集合示例  
List<int> dynamicList = new List<int>();  
dynamicList.Add(20); // 动态添加元素  

二、常用集合类型及其应用场景

2.1 List:动态数组的典范

List<T> 是 C# 中最常用的集合类型之一,它结合了数组的索引访问和动态扩展的能力。

核心方法与特性

  • Add():在末尾添加元素。
  • Remove():移除指定元素的第一个匹配项。
  • Contains():检查元素是否存在。
  • 索引访问:通过 list[index] 获取或修改元素。

示例:学生成绩管理

List<int> scores = new List<int>();  
scores.Add(85); // 添加成绩  
scores.Add(92);  

// 查找是否存在特定分数  
if (scores.Contains(90)) {  
    Console.WriteLine("存在90分");  
}  

// 遍历输出所有成绩  
foreach (int score in scores) {  
    Console.WriteLine(score);  
}  

性能注意事项

  • 插入/删除中间元素:时间复杂度为 O(n),因为需要移动后续元素。
  • 容量预分配:通过 List<T>.Capacity 可避免频繁扩容。

2.2 Dictionary<TKey, TValue>:键值对的高效管理

Dictionary<TKey, TValue> 用于存储键值对(Key-Value),通过唯一键快速检索值。

核心特性

  • 唯一键约束:每个键必须唯一,否则会抛出异常。
  • 快速查找:通过键访问值的时间复杂度为 O(1)。
  • 支持泛型:键和值均可指定类型(如 Dictionary<string, int>)。

示例:学生成绩字典

Dictionary<string, int> studentScores = new Dictionary<string, int>();  
studentScores.Add("Alice", 85);  
studentScores.Add("Bob", 92);  

// 通过键获取值  
int aliceScore = studentScores["Alice"]; // 输出85  

// 安全访问(避免KeyNotFoundException)  
if (studentScores.TryGetValue("Charlie", out int charlieScore)) {  
    Console.WriteLine(charlieScore);  
} else {  
    Console.WriteLine("未找到Charlie");  
}  

2.3 HashSet:无序且唯一的集合

HashSet<T> 用于存储不重复的元素,适用于需要快速判断元素存在性或去重的场景。

核心方法

  • Add():添加元素,若已存在则返回 false。
  • Contains():检查元素是否存在。
  • UnionWith():合并两个集合。

示例:去重用户输入

HashSet<string> uniqueWords = new HashSet<string>();  
string input = "apple,banana,apple,orange";  
foreach (string word in input.Split(',')) {  
    uniqueWords.Add(word.Trim()); // 自动去重  
}  

// 输出去重后的结果  
foreach (var word in uniqueWords) {  
    Console.WriteLine(word); // 仅输出apple、banana、orange  
}  

2.4 其他常用集合类型

集合类型适用场景
Queue<T>先进先出(FIFO)的队列,如任务调度
Stack<T>后进先出(LIFO)的栈,如递归模拟
LinkedList<T>频繁插入/删除中间元素的场景
SortedSet<T>自动排序且唯一元素的集合

三、集合的高级操作与性能优化

3.1 枚举器与遍历

集合通常通过枚举器(Enumerator) 实现遍历。开发者可以通过 foreach 循环或手动获取 GetEnumerator() 方法直接操作枚举器。

注意事项

  • 在遍历过程中不可修改集合(如添加或删除元素),否则会引发 InvalidOperationException
  • 若需在遍历时修改集合,可使用 ToList()ToArray() 创建副本。
// 安全遍历示例  
foreach (var item in myCollection.ToList()) {  
    if (item < 50) {  
        myCollection.Remove(item); // 直接操作原始集合  
    }  
}  

3.2 集合的排序与转换

通过 List<T>.Sort() 方法或 LINQ 查询,可以对集合进行排序或转换。

示例:按成绩降序排序

List<int> scores = new List<int> { 85, 92, 78, 95 };  
scores.Sort(); // 默认升序排序  

// 使用 LINQ 实现降序排序  
var sortedScores = scores.OrderByDescending(s => s).ToList();  

3.3 集合的线程安全

在多线程环境中,需使用线程安全的集合(如 ConcurrentQueue<T>)或手动加锁。

示例:线程安全的计数器

// 非线程安全的错误示例  
int count = 0;  
Parallel.For(0, 1000, _ => count++); // 可能导致数据不一致  

// 正确方式:使用线程安全的集合  
ConcurrentBag<int> concurrentCount = new ConcurrentBag<int>();  
Parallel.For(0, 1000, _ => concurrentCount.Add(1));  

四、最佳实践与常见误区

4.1 如何选择合适的集合类型?

  • 需要快速查找或更新键值对Dictionary<TKey, TValue>
  • 需要动态数组且频繁访问索引List<T>
  • 需要唯一元素且无需排序HashSet<T>
  • 需要频繁插入/删除中间元素LinkedList<T>

4.2 性能优化技巧

  • 预分配容量:对于 List<T>,通过 list.Capacity = estimatedSize 减少扩容开销。
  • 避免频繁的集合操作:在循环中,尽量减少 Contains() 调用,改用 HashSet<T> 提升效率。

4.3 常见误区

  • 错误 1:将非泛型集合(如 ArrayList)与泛型集合混用,导致类型转换错误。
  • 错误 2:在遍历时直接修改集合,引发异常。

结论

C# 集合(Collection)是开发者高效处理数据的核心工具。通过理解不同集合类型的特性(如 List<T> 的动态扩展、Dictionary 的键值对快速查找、HashSet 的唯一性约束),开发者可以针对具体场景选择最优方案。本文通过代码示例和性能分析,帮助读者掌握从基础到高级的集合用法,同时强调线程安全、内存管理和性能优化等关键点。掌握这些知识,将显著提升代码的健壮性和执行效率,为构建复杂应用程序奠定坚实基础。

如需进一步深入,可探索 LINQ 查询语法、集合的序列化,以及异步集合的高级用法。编程之路永无止境,但掌握集合的精髓,无疑是迈向专业开发的重要一步。

最新发布