在C#编程中,集合(Collections) 是存储和管理一组数据的重要数据结构。无论是简单的数组还是复杂的键值对存储,C#提供了丰富的集合类型来满足不同的需求。本文将全面介绍C#中的各种集合类型,包括非泛型集合、泛型集合、并发集合和不可变集合,并分析它们的适用场景、性能特点以及最佳实践。
在C#中,集合类型主要分为以下几类:
非泛型集合(System.Collections):早期版本提供的集合,可以存储任意类型的对象,但缺乏类型安全。
泛型集合(System.Collections.Generic):类型安全的集合,性能更优,推荐使用。
并发集合(System.Collections.Concurrent):线程安全的集合,适用于多线程环境。
不可变集合(System.Collections.Immutable):一旦创建就不能修改的集合,适用于函数式编程和并行计算。
非泛型集合可以存储任何类型的对象(object
),但由于它们不提供编译时类型检查,可能导致运行时错误。主要类型包括:
类似于数组,但可以动态调整大小。
存储的是object
类型,需要拆箱和装箱操作,影响性能。
ArrayList list = new ArrayList();
list.Add(10); // 存储整数
list.Add("Hello"); // 存储字符串
int num = (int)list[0]; // 需要显式转换
基于键值对存储,使用哈希算法提高查找速度。
键和值都是object
类型,存在类型安全问题。
Hashtable table = new Hashtable();
table.Add("Name", "Alice");
table.Add("Age", 25);
string name = (string)table["Name"]; // 需要类型转换
先进先出(FIFO) 结构,适用于任务调度。
Queue queue = new Queue();
queue.Enqueue("Task1");
queue.Enqueue("Task2");
string task = (string)queue.Dequeue(); // 返回 "Task1"
后进先出(LIFO) 结构,适用于撤销操作、递归算法等。
Stack stack = new Stack();
stack.Push("Item1");
stack.Push("Item2");
string item = (string)stack.Pop(); // 返回 "Item2"
按键排序的键值对集合,类似于Hashtable
,但保持有序。
SortedList sortedList = new SortedList();
sortedList.Add("Zebra", 100);
sortedList.Add("Apple", 200);
// 遍历时按键排序:Apple → Zebra
类型不安全:需要手动类型转换,可能导致运行时错误。
性能较低:由于使用object
,涉及拆箱/装箱操作。
推荐替代方案:尽量使用泛型集合(如List
、Dictionary
)。
泛型集合在C# 2.0引入,提供了类型安全和高性能的数据存储方式。常用类型包括:
类似于ArrayList
,但类型安全,性能更好。
List names = new List();
names.Add("Alice");
names.Add("Bob");
string first = names[0]; // 无需类型转换
基于哈希表的键值对集合,查找速度极快(O(1))。
Dictionary employees = new Dictionary();
employees.Add(1, "John");
employees.Add(2, "Mary");
string name = employees[2]; // 返回 "Mary"
类型安全的FIFO结构。
Queue numbers = new Queue();
numbers.Enqueue(10);
numbers.Enqueue(20);
int firstNum = numbers.Dequeue(); // 返回 10
类型安全的LIFO结构。
Stack stack = new Stack();
stack.Push("First");
stack.Push("Second");
string top = stack.Pop(); // 返回 "Second"
存储唯一元素,适用于去重操作。
HashSet uniqueNumbers = new HashSet();
uniqueNumbers.Add(1);
uniqueNumbers.Add(1); // 不会重复添加
Console.WriteLine(uniqueNumbers.Count); // 输出 1
支持高效插入和删除,但随机访问较慢(O(n))。
LinkedList linkedList = new LinkedList();
linkedList.AddLast("A");
linkedList.AddLast("B");
linkedList.AddFirst("C"); // 链表顺序:C → A → B
类型安全:编译时检查类型,减少运行时错误。
性能更高:避免拆箱/装箱操作。
推荐使用:在大多数情况下,优先选择泛型集合。
在多线程环境下,普通集合可能引发竞争条件(Race Condition)。C#提供了线程安全的并发集合:
适用于多线程环境下的数据存储。
ConcurrentBag bag = new ConcurrentBag();
Parallel.For(0, 10, i => bag.Add(i));
支持并发读写。
ConcurrentDictionary dict = new ConcurrentDictionary();
dict.TryAdd("Key1", 100);
dict.TryUpdate("Key1", 200, 100); // 更新值
适用于生产者-消费者模式,支持限制集合大小。
BlockingCollection queue = new BlockingCollection(boundedCapacity: 10);
// 生产者线程
Task.Run(() => { queue.Add(1); });
// 消费者线程
Task.Run(() => { int item = queue.Take(); });
多线程编程:如任务队列、并行计算。
避免锁竞争:比手动加锁(lock
)更高效。
不可变集合在创建后不能被修改,适用于函数式编程和高并发场景。
ImmutableList immutableList = ImmutableList.Create("A", "B");
ImmutableList newList = immutableList.Add("C"); // 返回新列表,原列表不变
ImmutableDictionary dict = ImmutableDictionary.Create();
dict = dict.Add(1, "One");
dict = dict.SetItem(1, "NewOne"); // 返回新字典
多线程安全:无需锁机制,天然线程安全。
函数式编程:避免副作用(Side Effects)。
需求 | 推荐集合 |
---|---|
动态数组 | List |
键值对存储 | Dictionary |
先进先出(FIFO) | Queue |
后进先出(LIFO) | Stack |
去重存储 | HashSet |
多线程安全 | ConcurrentDictionary |
不可变数据 | ImmutableList |
C#提供了丰富的集合类型,适用于不同的应用场景:
非泛型集合(已过时,不推荐使用)。
泛型集合(推荐,类型安全且高效)。
并发集合(适用于多线程)。
不可变集合(适用于函数式编程和高并发)。
在实际开发中,应根据性能、线程安全和数据访问模式选择合适的集合类型。泛型集合(如List
、Dictionary
)是最常用的选择,而并发集合和不可变集合则适用于特定场景。
希望本文能帮助你更好地理解C#集合类型,并在项目中做出更优的选择!