Dictionary在C#中需谨慎使用:默认非线程安全,Key重复Add会抛ArgumentException;应用dict[key]=value或TryAdd替代Add;TryGetValue比ContainsKey+索引器性能更优;自定义类作Key须重写GetHashCode和Equals或用record。

DictionaryArgumentException,且初始化后若未检查 ContainsKey 或用 TryGetValue 就访问值,运行时大概率崩。
为什么 Add 会报“给定键已经属于字典”?
这是最常踩的坑:把 Add 当成“有就更新、无就新增”,但它只做后者。一旦 Key 已存在,立刻抛出 ArgumentException: An item with the same key has already been added.。
- ✅ 正确做法:用
dict[key] = value赋值(自动覆盖)或先if (dict.ContainsKey(key)) dict[key] = value; - ✅ 更推荐:用
dict.TryAdd(key, value)(.NET 5+),只在 Key 不存在时添加,不抛异常 - ❌ 错误写法:
dict.Add("name", "Alice"); dict.Add("name", "Bob");—— 第二行必挂
TryGetValue 比 ContainsKey + 索引器 快在哪?
两次查找变一次。用 ContainsKey 判断后再取 dict[key],底层实际执行了两次哈希查找;而 TryGetValue 一次定位、同时返回是否成功和值,性能高且线程更友好。
- ✅ 推荐写法:
if (dict.TryGetValue("id123", out string name)) { Console.WriteLine(name); } - ❌ 不必要写法:
if (dict.ContainsKey("id123")) { Console.WriteLine(dict["id123"]); // 多一次哈希计算 - ⚠️ 注意:
out参数类型必须和TValue严格匹配,比如int?和int不能混用
如何让 Dictionary 支持自定义类作 Key?
默认情况下,自定义类作为 Key 会按引用比较,两个内容相同但不同实例的对象会被视为不同 Key —— 这通常不是你想要的。
- ✅ 必须重写
GetHashCode()和Equals(object obj),且逻辑要一致(例如都基于Id字段) - ✅ 更省事方案:让类继承
IEquatable,并实现GetHashCode - ✅ 最佳实践:用
record(C# 9+),它自动生成相等性成员,天然适合作为 Keypublic record Person(string Name, int Age);
var dict = new Dictionary(); dict[new Person("Tom", 25)] = "Engineer"; - ⚠️ 避坑:Key 对象的字段在加入字典后被修改,会导致哈希码变化,后续
TryGetValue找不到该 Key(查无此键)
真正难的不是“怎么初始化一个 Dictionary”,而是它在并发场景下会静默出错、Key 的生命周期管理容易被忽略、以及深嵌套结构中错误地复用同一个字典实例导致数据污染——这些都不会报编译错误,但会让调试时间翻倍。











