C#怎么使用Dictionary字典 C#如何用Dictionary存储键值对实现高效查找和遍历【基础】
C# Dictionary 使用指南:从泛型定义到线程安全,全面解析核心用法与最佳实践

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
Dictionary 初始化时必须指定泛型类型
在 C# 中直接声明 new Dictionary() 会导致编译失败。Dictionary 是一个强类型的泛型集合,必须明确指定键(TKey)和值(TValue)的具体类型。例如,创建字符串到用户对象的映射,应写作 new Dictionary。避免使用 new Dictionary() 或 new Dictionary 这类写法,后者虽能编译,但会破坏类型安全并引发不必要的装箱拆箱性能损耗。
未指定泛型参数通常会引发编译错误 CS0305,或在运行时抛出 InvalidCastException 类型转换异常。
- 键类型的选择原则:推荐使用不可变且已正确实现
GetHashCode()与Equals()方法的类型作为键,例如string、int、Guid等,这些是理想的字典键类型。 - 自定义类作为键的注意事项:若使用自定义类作为键,必须重写
GetHashCode()和Equals()方法,否则字典将基于对象引用进行相等性比较,导致查找逻辑错误。 - 避免使用可变键:切勿使用内容可变的引用类型(如未重写相关方法的
List)作为键。键值一旦被修改,其哈希码可能改变,导致该键在字典中无法被正确检索。
添加和查找键值对必须注意 KeyNotFoundException
通过索引器直接访问值,如 dict[“abc”],是常见的错误用法。若键“abc”不存在,程序将抛出 KeyNotFoundException 异常,而非返回 null 或默认值。这在不确定键是否存在的业务场景中风险极高。
正确的字典值获取方式主要分为以下三种情况:
- 场景一:明确知道键存在。可直接使用
dict[key],这种方式最为简洁且性能最佳,但前提是程序逻辑必须确保该键已被添加。 - 场景二:不确定键是否存在,且需要获取对应值。强烈推荐使用
dict.TryGetValue(key, out value)方法。它返回一个布尔值指示查找是否成功,并通过out参数返回找到的值。这种方法避免了异常抛出,且经过性能优化,是兼顾安全与效率的首选。 - 场景三:仅需判断键是否存在,无需获取值。可使用
dict.ContainsKey(key)方法。但需注意,其内部可能执行额外的哈希计算,通常比TryGetValue略慢。若非仅需判断存在性,更推荐使用TryGetValue。
以下是一个典型的安全取值示例:
if (users.TryGetValue(“U1001”, out var user))
{
Console.WriteLine(user.Name);
}
else
{
Console.WriteLine(“用户不存在”);
}
遍历 Dictionary 推荐用 foreach + KeyValuePair 而非 Keys/Values 分离
在需要同时遍历键和值时,应避免使用 foreach (var key in dict.Keys) { var val = dict[key]; ... } 这种模式。其问题在于,对每个键都会执行两次哈希查找(一次在 Keys 集合中,一次通过索引器),造成不必要的性能开销,且在并发修改时可能引发错误。
更高效且优雅的做法是直接遍历字典本身,它会返回一系列 KeyValuePair 结构体:
- 标准遍历写法:使用
foreach (var kvp in dict),然后通过kvp.Key和kvp.Value访问键值对。这是最清晰、最常用的方式。 - 解构遍历写法(C# 7及以上):若追求代码简洁,可使用元组解构语法:
foreach (var (id, user) in dict)。这种方式要求键值类型明确,使代码意图一目了然。 - 应避免的写法:不要为了遍历而调用
dict.Keys.ToList()或类似方法。这会创建不必要的中间集合,导致额外的内存分配,并丢失字典原有的结构语义。
Dictionary 不是线程安全的,多线程读写必须加锁或换 ConcurrentDictionary
这是一个关键的安全警告:标准的 Dictionary 类不是线程安全的。当多个线程同时执行添加、删除或某些读取操作时,可能导致其内部数据结构损坏,进而引发 InvalidOperationException 异常或返回错误数据。即使是“读多写少”的场景,只要存在任何写操作,就必须对普通 Dictionary 进行同步保护。
请注意,即便只是并发读取,在字典内部因容量不足而触发扩容重建时,也可能导致不可预知的问题。
处理多线程并发访问字典,主要有两种主流方案:
- 手动同步(使用锁):使用
lock语句块包裹所有对字典的读写操作。建议使用一个私有的、只读的对象作为锁对象,避免直接锁定this或字典实例本身,以降低死锁风险。 - 使用线程安全集合:直接替换为
ConcurrentDictionary。该类内部采用了更精细的锁机制(如分段锁),使得大多数读操作可以无锁进行,写操作的锁竞争也更小,性能更优。但需注意,其GetOrAdd、AddOrUpdate等方法接收的工厂委托可能会被多次执行,因此不应在委托内编写具有副作用的逻辑。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
Python环境下PyTorch怎么实现知识蒸馏_构建教师模型引导学生学习
PyTorch知识蒸馏实战指南:教师模型指导学生模型高效学习 知识蒸馏技术能够将大型教师模型的知识压缩到小型学生模型中,是实现模型轻量化的有效手段。然而,许多开发者在PyTorch中实现知识蒸馏时,常因忽略关键细节导致训练失败或效果不佳。本文将深入剖析这些核心要点,提供一份清晰、可落地的实践指南,帮
Go 中错误处理的惯用法:如何写出简洁、健壮且符合 Go 风格的错误处理代码
Go 语言错误处理最佳实践:编写简洁、健壮且符合 Go 风格的代码指南 Go 语言采用多返回值(值 + error)实现显式错误处理,其标准做法是在每次函数调用后立即检查 err 是否为 nil;虽然忽略错误在语法上可行,但这违背了 Go 的设计哲学,极易导致隐蔽的 panic 或难以追踪的逻辑错误
Python编写Flask接口如何限制请求频率_使用Flask-Limiter防止接口滥用
Python Flask接口请求频率限制实战:Flask-Limiter防刷指南 Flask-Limiter 初始化配置详解:避免应用上下文错误 应用上下文配置不当,是开发者初次集成 Flask-Limiter 时最常见的错误。核心症结在于,限流器必须在 Flask 应用实例完全初始化且应用上下文就
Python程序PyTorch显存泄漏怎么办_利用torch.cuda.empty_cache清理
torch cuda empty_cache() 仅释放未被张量引用的缓存显存,不回收仍被变量或模型持有的显存;需配合 del、zero_grad() 和 no_grad() 才能有效释放。 为什么 torch cuda empty_cache() 经常不起作用? 简单来说,这个函数的作用范围非常有
如何在 WooCommerce 中隐藏无缩略图的产品
如何在 WooCommerce 中隐藏无缩略图的产品 本文详细讲解如何通过自定义代码过滤 WooCommerce 商品查询,自动排除未设置特色图像(产品主图)的商品,确保店铺前台仅展示带有有效产品图片的商品条目,提升页面美观度与专业感。 你是否希望自己的 WooCommerce 在线商店前台只呈现那
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

