c# dictionary必须指定泛型类型,否则编译报错cs0305;键需不可变且重写gethashcode和equals;取值优先用trygetvalue避免keynotfoundexception;遍历应直接foreach(var kvp in dict);多线程须用concurrentdictionary或加锁。

直接用 Dictionary<tkey tvalue></tkey> 就行,但必须写全泛型参数,否则编译失败;不确定键是否存在时,别用 dict[key],改用 TryGetValue;遍历时别拆 Keys 和 Values,直接 foreach (var kvp in dict)。
为什么 new Dictionary() 会编译报错 CS0305
C# 的 Dictionary 是泛型类,TKey 和 TValue 都不能省。写 new Dictionary() 相当于没告诉编译器“键是什么类型、值是什么类型”,它没法做类型检查和内存布局——所以直接报错 CS0305。
- 正确写法:比如存用户 ID(
string)到用户对象(User),就得是new Dictionary<string user>()</string> - 错误写法:
new Dictionary()、new Dictionary<object object>()</object>(后者虽能编译,但失去类型安全,还触发装箱) - 自定义类作键时,必须重写
GetHashCode()和Equals(),否则ContainsKey或TryGetValue会查不到——因为哈希值变了或比较逻辑不匹配
访问值时 KeyNotFoundException 怎么避
dict["abc"] 这种索引器访问,只要键不存在,就抛 KeyNotFoundException。这不是“异常难处理”,而是设计上就要求你明确知道键一定存在——实际业务里几乎从不满足这个前提。
- 确定存在且追求性能:用
dict[key](比如刚Add完立刻取) - 不确定是否存在,又需要值:用
dict.TryGetValue(key, out value),返回bool,不抛异常,性能也略优于ContainsKey+ 索引器组合 - 只判断存在性:用
dict.ContainsKey(key),但注意它比TryGetValue多一次哈希查找
示例:
if (users.TryGetValue("U1001", out var user))
{
Console.WriteLine(user.Name);
}
else
{
Console.WriteLine("用户不存在");
}
遍历 Dictionary 为什么不能 foreach (var key in dict.Keys)
写 foreach (var key in dict.Keys) { var val = dict[key]; } 表面上没问题,实际做了两件事:先遍历所有键,再对每个键重新哈希查找一次值——等于把 O(1) 查找硬拖成 O(n) × 2,性能白丢一半;而且在多线程或迭代中修改字典时,可能触发 InvalidOperationException。
- 正确方式:直接遍历字典本身,它返回的是
KeyValuePair<tkey tvalue></tkey> - 推荐写法:
foreach (var kvp in dict),然后用kvp.Key和kvp.Value - 如果只想要键或只想要值,再用
dict.Keys或dict.Values,但别混着用
并发读写必须换 ConcurrentDictionary 吗
普通 Dictionary 不是线程安全的:多个线程同时读+写、或同时写,大概率崩——不是数据错,是直接抛 InvalidOperationException 或内部状态损坏。
- 纯读多写少:加
lock也能用,但锁粒度大,影响吞吐 - 读写都频繁:直接换
ConcurrentDictionary<tkey tvalue></tkey>,它内部用分段锁+无锁技巧,GetOrAdd、AddOrUpdate这些方法才是为并发设计的 - 别试图用
ReadOnlyDictionary来“保护”可变字典——它只是包装层,底层数组仍可被原引用修改
最常被忽略的一点:哪怕只是“看起来只读”的字典,只要它的引用被多个线程拿到,且其中任一线程可能修改它,就必须考虑线程安全——类型系统不会替你拦住那个 dict["x"] = y。











