C# 数据结构和特殊类型及适用场景

 更新时间:2026年11月10日 09:47:49   作者:Windrunner01  
‌C#的数据结构主要分两大类:值类型和引用类型‌,日常开发中常用的集合类都在 System.Collections.Generic 命名空间下,本文介绍C# 数据结构和特殊类型的相关知识,感兴趣的朋友一起看看吧

.NET Core(现统称为 .NET)提供了丰富的数据结构和特殊类型,旨在优化性能、内存管理以及开发效率。

常用集合与数据结构

线性结构

Array (T[])

特点:

  • 内存连续分配,元素类型固定,长度不可变。
  • 支持索引快速访问,读取速度极快。
  • 增删元素效率低(需移动后续元素),长度固定。

数组是固定大小的连续内存块。‌不支持动态增删‌,只能修改元素或创建新数组。

int[] arr = new int[5] { 1, 2, 3, 4, 5 };
// 【查】通过索引访问 O(1)
int val = arr[0]; 
// 【改】直接赋值
arr[0] = 10;
// 【增/删】数组本身不支持。需借助 Array.Resize 或 LINQ 创建新数组
// 模拟“添加”:创建更大的数组并复制
Array.Resize(ref arr, arr.Length + 1);
arr[arr.Length - 1] = 6;
// 模拟“删除”:通常使用 LINQ 过滤生成新数组
arr = arr.Where(x => x != 3).ToArray();

List

最常用的动态数组,支持索引访问。

特点:

  • 动态数组,底层基于 Array 实现,但长度可变。
  • 兼顾了读取速度(索引访问)和灵活性(自动扩容)。是日常开发中最常用的集合。
  • 在列表中间插入或删除元素时,需要移动大量数据,性能较差。
List<string> list = new List<string> { "A", "B", "C" };
// 【增】
list.Add("D");           // 尾部添加 O(1)
list.Insert(0, "Start"); // 指定位置插入 O(n)
// 【查】
string item = list[0];   // 索引访问 O(1)
bool exists = list.Contains("B"); // 线性查找 O(n)
string found = list.Find(x => x.StartsWith("A")); // 条件查找
// 【改】
list[0] = "Modified";    // 索引赋值
// 若元素是引用类型,可直接修改属性: list[0].Name = "New";
// 【删】
list.Remove("B");        // 删除第一个匹配项 O(n)
list.RemoveAt(0);        // 按索引删除 O(n)
list.RemoveAll(x => x.Length < 2); // 批量删除

ArrayList

存储 object 类型,存在装箱/拆箱性能损耗,无类型安全。

特点:

  • 非泛型集合,元素被视为 object。
  • 存储值类型时会发生装箱/拆箱操作,影响性能且类型不安全。建议优先使用 List<T>。
using System.Collections;
ArrayList arrayList = new ArrayList();
// 【增】
arrayList.Add(1);       // 装箱
arrayList.Add("Text");
// 【查】
int first = (int)arrayList[0]; // 拆箱,需强制转换
// 【改】
arrayList[0] = 100;
// 【删】
arrayList.Remove(100);
arrayList.RemoveAt(0);

LinkedList

双向链表,适合频繁在中间插入/删除,不支持索引访问。

特点:

  • 双向链表,内存不连续。
  • 在任意位置插入和删除元素非常快(只需修改指针)。
  • 不支持索引访问,遍历查找慢。
LinkedList<int> linkedList = new LinkedList<int>(new[] { 1, 2, 3 });
// 【增】
linkedList.AddFirst(0);
linkedList.AddLast(4);
LinkedListNode<int> node = linkedList.Find(2);
if (node != null) linkedList.AddAfter(node, 5); // 在节点后插入 O(1)
// 【查】
// 不支持索引 linkedList[0] 是错误的
bool exists = linkedList.Contains(2); // O(n)
LinkedListNode<int> foundNode = linkedList.Find(2); // O(n)
// 【改】
if (foundNode != null) foundNode.Value = 20;
// 【删】
linkedList.Remove(20);      // 按值删除 O(n)
linkedList.RemoveFirst();   // O(1)
linkedList.RemoveLast();    // O(1)
if (node != null) linkedList.Remove(node); // 按节点删除 O(1)

栈与队列

Stack

特点:后进先出(LIFO)结构。常用于表达式求值、撤销操作等场景。

Stack<string> stack = new Stack<string>();
// 【增】
stack.Push("A");
stack.Push("B");
// 【查】仅能查看栈顶
string top = stack.Peek(); // 不移除
// 【删】仅能移除栈顶
string popped = stack.Pop();
// 注意:Stack 没有 Indexer,不能 stack[0],也不能直接修改中间元素

Queue

特点:先进先出(FIFO)结构。常用于任务排队、广度优先搜索等场景。

Queue<string> queue = new Queue<string>();
// 【增】
queue.Enqueue("A");
queue.Enqueue("B");
// 【查】仅能查看队头
string head = queue.Peek();
// 【删】仅能移除队头
string dequeued = queue.Dequeue();
// 注意:Queue 同样不支持随机访问或修改中间元素

键值对与集合

Dictionary<TKey, TValue>

特点:

  • 基于哈希表实现。
  • 通过 Key 查找 Value 的速度极快(接近 O(1))。
  • Key 必须唯一且不可变(或正确重写 GetHashCode 和 Equals)。

基于哈希表,Key 唯一。

Dictionary<int, string> dict = new Dictionary<int, string>();
// 【增】
dict.Add(1, "One");
dict[2] = "Two"; // 若 Key 存在则覆盖,不存在则添加
// 【查】
string val = dict[1];          // 若 Key 不存在抛异常
bool hasKey = dict.ContainsKey(1); // 推荐先检查
bool tryGet = dict.TryGetValue(3, out string result); // 安全获取
// 【改】
dict[1] = "Updated One"; // 直接赋值覆盖
// 【删】
dict.Remove(1);

HashSet

基于哈希表,元素唯一,无序。

特点:

  • 基于哈希表实现的集合,不包含重复元素。
  • 快速判断元素是否存在,适合去重操作。
HashSet<string> set = new HashSet<string>();
// 【增】
set.Add("A"); // 返回 bool,若已存在则返回 false 且不添加
// 【查】
bool exists = set.Contains("A"); // O(1)
// 【改】 HashSet 不支持直接“修改”元素。
// 若要修改,需先 Remove 再 Add
set.Remove("A");
set.Add("B");
// 【删】
set.Remove("A");
set.Clear();

SortedDictionary<TKey, TValue> / SortedSet

基于红黑树,Key/元素自动排序。

特点:

  • 基于红黑树实现,元素自动排序。
  • 遍历时有序,适合需要范围查询的场景。
// SortedDictionary
SortedDictionary<int, string> sortedDict = new SortedDictionary<int, string>();
sortedDict.Add(3, "C");
sortedDict.Add(1, "A");
// 遍历按键排序: 1->A, 3->C
// 增删改查方法与 Dictionary 类似,但复杂度为 O(log n)
// SortedSet
SortedSet<int> sortedSet = new SortedSet<int>();
sortedSet.Add(5);
sortedSet.Add(1);
// 自动排序: 1, 5
// 支持范围操作
var subset = sortedSet.GetViewBetween(1, 10); 

ConcurrentDictionary<TKey, TValue>

线程安全字典,适用于多线程。

特点:线程安全的字典,适用于多线程并发环境。

using System.Collections.Concurrent;
ConcurrentDictionary<int, string> concDict = new ConcurrentDictionary<int, string>();
// 【增/改】原子操作
concDict.TryAdd(1, "A"); // 仅当 Key 不存在时添加
concDict[1] = "B";       // 直接赋值(线程安全但不保证原子性逻辑)
concDict.AddOrUpdate(1, "New", (key, oldVal) => "Updated"); // 原子性添加或更新
// 【查】
bool success = concDict.TryGetValue(1, out string val);
// 【删】
concDict.TryRemove(1, out string removedVal);

高性能与特殊类型

Span<T> 和 Memory<T> 主要用于‌切片和读取‌,它们‌不提供‌传统集合的 Add/Remove 方法,因为底层内存大小通常是固定的或受管理的。

为了提升系统性能和内存效率,.NET Core 引入了一些特殊的类型和结构:

内存优化类型

Span

栈上分配,高性能切片。

特点:

  • 表示连续内存区域的任意切片。它是一个 ref struct(引用结构体),存储在栈上。
  • 允许在不分配新内存的情况下,安全地操作数组、字符串或原生内存的一部分。
  • 高性能字符串处理、网络包解析、大数据集切片。它避免了不必要的内存分配和复制,显著减少 GC 压力。
int[] array = { 1, 2, 3, 4, 5 };
Span<int> span = array.AsSpan();
// 【查】
int first = span[0];
Span<int> subSpan = span.Slice(1, 2); // 获取子视图 [2, 3]
// 【改】
span[0] = 10; // 直接修改底层数组
// 【增/删】不支持。Span 长度固定。
// 若需“扩容”,必须分配新的数组或 Span。

Memory

堆上分配,可用于异步场景。

特点:

  • 与 Span<T> 类似,但可以存储在堆上(例如作为类字段或异步方法中的局部变量)。
  • 当需要在异步操作中持有内存引用时使用。
Memory<int> memory = new Memory<int>(new int[] { 1, 2, 3 });
// 【查】
int val = memory.Span[0]; // 通过 .Span 属性访问
// 【改】
memory.Span[0] = 10;
// 【增/删】不支持。同 Span,需重新分配内存。

基本数据类型

如 Int32 (int), Byte, Char, Boolean 等,均对应 CLR 中的值类型,存储在栈上(除非被装箱或作为对象字段)。

其他类型

String

虽然是引用类型,但在 .NET 中具有不可变性(Immutable)和驻留池(Interning)机制。

Nullable (T)

允许值类型(如 int, bool)拥有 null 值,增强了数据表达的灵活性。

其他特殊结构

Tuple / ValueTuple

用于轻量级地组合多个数据项,无需定义专门的类。ValueTuple 是值类型,性能更优。

// ValueTuple (推荐,值类型,性能高)
var person = (Id: 1, Name: "Alice");
// 【改】无法直接修改字段,需重新赋值
person = person with { Name = "Bob" }; // C# 10+ 支持 with 表达式用于元组
// 或者
person = (1, "Bob");
// 【查】
string name = person.Name;

Record(C9+)

一种特殊的引用类型(或结构体记录),主要用于不可变数据模型,自动生成相等性比较逻辑,适合 DTO(数据传输对象)。

public record Person(int Id, string Name);
var p1 = new Person(1, "Alice");
// 【改】使用 with 表达式创建修改后的副本(非破坏性更新)
var p2 = p1 with { Name = "Bob" };
// 【查】
Console.WriteLine(p2.Name);
// 【增/删】不适用,Record 是单个对象,不是集合。

接口

IEnumerable

所有集合的基础,支持 foreach 迭代(迭代器模式)。

只读,仅支持遍历。

IEnumerable<int> enums = new List<int> { 1, 2, 3 };
// 【查】仅支持 foreach 或 LINQ
foreach (var item in enums) { }
// 无 Add, Remove, Indexer

ICollection

继承自 IEnumerable,提供 Count、Add、Remove 等基本操作。

支持计数、添加、删除、清空。

ICollection<string> coll = new List<string>();
coll.Add("A");      // 【增】
coll.Remove("A");   // 【删】
coll.Clear();       // 【删所有】
int count = coll.Count; // 【查数量】
// 不支持索引访问 coll[0] 是错误的

IList

继承自 ICollection,支持索引访问(如 List)。

IList<string> listInterface = new List<string>();
listInterface.Add("A");     // 【增】
listInterface[0] = "B";     // 【改/查】索引器
listInterface.RemoveAt(0);  // 【删】
// 包含 Insert, IndexOf 等方法

IDictionary<TKey, TValue>

键值对集合的标准接口。

IDictionary<int, string> dictInterface = new Dictionary<int, string>();
dictInterface.Add(1, "A");      // 【增】
dictInterface[1] = "B";         // 【改】
string val = dictInterface[1];  // 【查】
dictInterface.Remove(1);        // 【删】

总结

  • 日常开发:首选 List<T> 和 Dictionary<TKey, TValue>。
  • 高性能场景:涉及大量字符串或数组切片操作时,使用 Span<T> 和 Memory<T> 以减少内存分配。
  • 并发场景:使用 ConcurrentDictionary 或 ConcurrentQueue 等线程安全集合。
  • 避免使用:尽量避免使用非泛型的 ArrayList 和 Hashtable,除非为了兼容极旧的代码。
需求场景推荐类型关键方法
‌通用动态列表‌List<T>Add, RemoveAt, [i]
‌快速键值查找‌Dictionary<K,V>TryGetValue, Add, Remove
‌去重集合‌HashSet<T>Add, Contains, Remove
‌有序键值对‌SortedDictionary<K,V>同 Dictionary,自动排序
‌多线程共享‌ConcurrentDictionaryTryAdd, TryRemove, AddOrUpdate
‌高性能切片/解析‌Span<T> / Memory<T>Slice, [i] (只读/修改,无增删)
‌先进先出队列‌Queue<T>Enqueue, Dequeue, Peek
‌后进先出栈‌Stack<T>Push, Pop, Peek

到此这篇关于C# 数据结构和特殊类型及适用场景的文章就介绍到这了,更多相关C# 数据结构和特殊类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C# wpf实现任意控件更多调整大小功能

    C# wpf实现任意控件更多调整大小功能

    这篇文章主要为大家详细介绍了C# wpf实现任意控件更多调整大小功能的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01
  • C#利用性能计数器监控网络状态

    C#利用性能计数器监控网络状态

    这篇文章主要为大家详细介绍了C#利用性能计数器监控网络状态的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • c# 网络编程之http

    c# 网络编程之http

    这篇文章主要介绍了c# 提供一个HTTP服务的实现示例,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下
    2021-02-02
  • Unity利用材质自发光实现物体闪烁

    Unity利用材质自发光实现物体闪烁

    这篇文章主要为大家详细介绍了Unity利用材质自发光实现物体闪烁,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • C#绘制中国象棋棋盘

    C#绘制中国象棋棋盘

    这篇文章主要为大家详细介绍了C#绘制中国象棋棋盘,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • C# 通过NI-VISA操作Tektronix TBS 2000B系列示波器的实现步骤

    C# 通过NI-VISA操作Tektronix TBS 2000B系列示波器的实现步骤

    这篇文章主要介绍了C# 通过NI-VISA操作Tektronix TBS 2000B系列示波器的实现步骤,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-02-02
  • 如何使用C#从word文档中提取图片

    如何使用C#从word文档中提取图片

    图片和文字是word文档中两种最常见的对象,在微软word中,如果我们想要提取出一个文档内的图片,只需要右击图片选择另存为然后命名保存就可以了,今天这篇文章主要是实现如何使用C#从word文档中提取图片,需要的朋友参考下
    2016-02-02
  • C# TrackBar拖动条改变滑块颜色

    C# TrackBar拖动条改变滑块颜色

    这篇文章主要为大家详细介绍了C# TrackBar拖动条改变滑块颜色,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C#调用OpenXml合并word文档中的表格单元格

    C#调用OpenXml合并word文档中的表格单元格

    这篇文章主要为大家详细介绍了C#如何调用OpenXml合并word文档中的表格单元格,文中的示例代码讲解详细,有需要的小伙伴可以参考一下
    2025-10-10
  • C#算法之实现阿姆斯特朗数

    C#算法之实现阿姆斯特朗数

    这篇文章介绍了C#实现阿姆斯特朗数的算法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-02-02

最新评论