普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月14日首页

C# Dictionary 入门:用键值对告别低效遍历

作者 烛阴
2025年12月13日 19:25

一、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”的情况
  • 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. KeysValues:获取所有 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# 技术干货!如果觉得有用,记得收藏本文

❌
❌