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

一、Dictionary 是什么

Dictionary<TKey, TValue>

  • 一个"键值对"集合
  • 通过 Key 快速查 Value
  • 查找、添加、删除的平均复杂度接近 O(1)
  • 底层是哈希表(hash table)

典型场景:

  • 用户ID(Key) → 用户对象(Value)
  • 商品编码 → 商品信息
  • 配置项名称 → 配置值
  • 状态码 → 描述字符串

命名空间在:

csharp 复制代码
using System.Collections.Generic;

二、如何创建一个 Dictionary

1. 无参构造

csharp 复制代码
var dict = new Dictionary<string, int>();

含义:

  • Key 类型:string
  • Value 类型:int
  • 初始容量默认(会按需要自动扩容)

2. 指定初始容量(推荐在数据量较大时用)

csharp 复制代码
var dict = new Dictionary<string, int>(capacity: 1000);

好处:

  • 减少扩容次数,性能更稳定
  • 适合"我大概知道会放多少条数据"的场景

3.直接初始化一些数据(集合初始化器)

csharp 复制代码
var dict = new Dictionary<string, int>
{
    { "apple", 3 },
    { "banana", 5 },
};

还可以用索引器形式:

csharp 复制代码
var dict = new Dictionary<string, int>
{
    ["apple"] = 3,
    ["banana"] = 5,
};

三、日常要用到的基本操作

csharp 复制代码
var stock = new Dictionary<string, int>();

1. 添加:Add vs 直接用索引器

csharp 复制代码
// 方式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

csharp 复制代码
// 已经有一些数据
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. 修改:直接给索引器赋值即可

csharp 复制代码
// 已有 "apple" → 10
stock["apple"] = 15; // 覆盖为 15

如果你想"在原有值上累加",可以搭配 TryGetValue

csharp 复制代码
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

csharp 复制代码
// 删除某个键值对
bool removed = stock.Remove("apple");   // 删除成功返回 true,不存在返回 false

// 清空所有数据
stock.Clear();

四、几个非常重要的属性和方法

1. Count:当前元素个数

csharp 复制代码
Console.WriteLine(stock.Count);

2. KeysValues:获取所有 Key / Value

csharp 复制代码
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

csharp 复制代码
bool hasApple = stock.ContainsKey("apple");
bool hasCount10 = stock.ContainsValue(10);

区别与性能:

  • ContainsKey:平均 O(1),很快
  • ContainsValue:需要遍历所有 Value,O(n),大字典慎用

五、如何正确遍历 Dictionary

1. 遍历键值对

csharp 复制代码
foreach (var kv in stock)
{
    Console.WriteLine($"水果:{kv.Key},库存:{kv.Value}");
}

2. 解构写法

csharp 复制代码
foreach (var (name, count) in stock)
{
    Console.WriteLine($"{name} => {count}");
}

3. 只遍历 Key 或只遍历 Value

csharp 复制代码
foreach (var name in stock.Keys)
{
    Console.WriteLine(name);
}

foreach (var count in stock.Values)
{
    Console.WriteLine(count);
}

4. 注意:遍历时不要直接修改字典

下面这种写法在运行时会抛 InvalidOperationException

csharp 复制代码
foreach (var (name, count) in stock)
{
    if (count == 0)
    {
        stock.Remove(name); // 遍历中修改集合 → 异常
    }
}

正确写法之一:先记录要删的 Key,再统一删:

csharp 复制代码
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# 技术干货!如果觉得有用,记得收藏本文

相关推荐
极速蜗牛3 小时前
告别部署焦虑!PinMe:前端开发者的极简部署神器
前端·javascript
uhakadotcom4 小时前
Python Protobuf 全面教程:常用 API 串联与实战指南
前端·面试·github
by__csdn4 小时前
微前端架构:从理论到实践的全面解析
前端·javascript·vue.js·架构·typescript·vue·ecmascript
漫长的~以后4 小时前
Edge TPU LiteRT V2拆解:1GB内存设备也能流畅跑AI的底层逻辑
前端·人工智能·edge
小福气_4 小时前
自定义组件 vue3+elementPlus
前端·javascript·vue.js
piaoroumi4 小时前
UVC调试
linux·运维·前端
Monkey_Xuan4 小时前
C#中的引用传递和值传递
unity·c#
前端不太难4 小时前
RN 调试效率低,一点小改动就需要重新构建?解决手册(实战 / 脚本 / Demo)
前端·react native·重构
是谁眉眼4 小时前
vue环境变量
前端·javascript·vue.js