C# Dictionary 入门:用键值对告别低效遍历
一、Dictionary 是什么
Dictionary<TKey, TValue>:
- 一个“键值对”集合
- 通过 Key 快速查 Value
- 查找、添加、删除的平均复杂度接近 O(1)
- 底层是哈希表(hash table)
典型场景:
- 用户ID(Key) → 用户对象(Value)
- 商品编码 → 商品信息
- 配置项名称 → 配置值
- 状态码 → 描述字符串
命名空间在:
using System.Collections.Generic;
二、如何创建一个 Dictionary
1. 无参构造
var dict = new Dictionary<string, int>();
含义:
- Key 类型:
string - Value 类型:
int - 初始容量默认(会按需要自动扩容)
2. 指定初始容量(推荐在数据量较大时用)
var dict = new Dictionary<string, int>(capacity: 1000);
好处:
- 减少扩容次数,性能更稳定
- 适合“我大概知道会放多少条数据”的场景
3.直接初始化一些数据(集合初始化器)
var dict = new Dictionary<string, int>
{
{ "apple", 3 },
{ "banana", 5 },
};
还可以用索引器形式:
var dict = new Dictionary<string, int>
{
["apple"] = 3,
["banana"] = 5,
};
三、日常要用到的基本操作
var stock = new Dictionary<string, int>();
1. 添加:Add vs 直接用索引器
// 方式1:Add
stock.Add("apple", 10);
stock.Add("banana", 5);
// 方式2:索引器
stock["orange"] = 8; // orange 不存在时 → 添加
stock["orange"] = 12; // orange 已存在时 → 覆盖为 12
区别:
-
Add(key, value):- 如果 Key 已经存在,会抛
ArgumentException - 适合“逻辑上不该有重复 Key,有就是 Bug”的情况
- 如果 Key 已经存在,会抛
-
stock[key] = value:- Key 不存在 → 添加
- Key 已存在 → 覆盖
- 适合“重复 Key 表示更新”的场景
2. 读取:索引器 vs TryGetValue
// 已经有一些数据
stock["apple"] = 10;
// 方式1:索引器
int appleCount = stock["apple"]; // 如果 apple 不存在会抛 KeyNotFoundException
// 方式2:TryGetValue(推荐)
if (stock.TryGetValue("banana", out int bananaCount))
{
Console.WriteLine($"banana: {bananaCount}");
}
else
{
Console.WriteLine("banana 不存在");
}
使用建议:
- 确定 Key 一定存在 → 可以直接用索引器
- 不确定 Key 是否存在 → 优先用
TryGetValue,防止异常
3. 修改:直接给索引器赋值即可
// 已有 "apple" → 10
stock["apple"] = 15; // 覆盖为 15
如果你想“在原有值上累加”,可以搭配 TryGetValue:
void AddStock(string name, int delta)
{
stock.TryGetValue(name, out int current); // 不存在时 current=0
stock[name] = current + delta;
}
// 用法:
AddStock("apple", 5); // apple: 10 → 15
AddStock("pear", 3); // pear: 0 → 3(新增)
4. 删除:Remove / Clear
// 删除某个键值对
bool removed = stock.Remove("apple"); // 删除成功返回 true,不存在返回 false
// 清空所有数据
stock.Clear();
四、几个非常重要的属性和方法
1. Count:当前元素个数
Console.WriteLine(stock.Count);
2. Keys 和 Values:获取所有 Key / Value
var keys = stock.Keys; // ICollection<string>
var values = stock.Values; // ICollection<int>
stock["apple"] = 33;
foreach (var name in stock.Keys)
{
Console.WriteLine(name);
}
foreach (var count in stock.Values)
{
Console.WriteLine(count);
}
注意:
-
Keys/Values是引用,不是复制品 - 修改原字典,这两个集合感知得到变化
3. ContainsKey / ContainsValue
bool hasApple = stock.ContainsKey("apple");
bool hasCount10 = stock.ContainsValue(10);
区别与性能:
-
ContainsKey:平均 O(1),很快 -
ContainsValue:需要遍历所有 Value,O(n),大字典慎用
五、如何正确遍历 Dictionary
1. 遍历键值对
foreach (var kv in stock)
{
Console.WriteLine($"水果:{kv.Key},库存:{kv.Value}");
}
2. 解构写法
foreach (var (name, count) in stock)
{
Console.WriteLine($"{name} => {count}");
}
3. 只遍历 Key 或只遍历 Value
foreach (var name in stock.Keys)
{
Console.WriteLine(name);
}
foreach (var count in stock.Values)
{
Console.WriteLine(count);
}
4. 注意:遍历时不要直接修改字典
下面这种写法在运行时会抛 InvalidOperationException:
foreach (var (name, count) in stock)
{
if (count == 0)
{
stock.Remove(name); // 遍历中修改集合 → 异常
}
}
正确写法之一:先记录要删的 Key,再统一删:
var toRemove = new List<string>();
foreach (var (name, count) in stock)
{
if (count == 0)
toRemove.Add(name);
}
foreach (var name in toRemove)
{
stock.Remove(name);
}
结语
点个赞,关注我获取更多实用 C# 技术干货!如果觉得有用,记得收藏本文