C# IDictionary和Dictionary

介绍

在C#编程中,IDictionary<TKey, TValue> 和 Dictionary<TKey, TValue> 是处理键值对集合时常用的类型。下面将详细介绍它们的概念、区别及应用场景,并提供相应的代码示例。

见下面的两张身份证图片,观察区别,哪个身份证更加易于理解

“姓名”、“性别”就是key,与之对应的具体内容就是value

类比Java

IDictionary 相当于 Map
Dictionary 相当于 HashMap

1. IDictionary 接口

概念

  • 定义:IDictionary<TKey, TValue> 是一个泛型接口,定义了操作键值对集合的基本方法和属性。
  • 特点:
    • 键必须唯一,且不能为 null(除非 TKey 是引用类型)。
    • 值可以重复或为 null。
    • 提供了添加、删除、查找元素等方法。
  • 应用场景:当需要编写通用代码,支持不同字典实现时使用。

常用方法和属性

成员 描述
Add(key, value) 添加键值对。
ContainsKey(key) 检查是否包含指定键。
Remove(key) 移除指定键的元素。
TryGetValue(key, out value) 获取键对应的值(安全方式)。
this[key] 通过索引器访问或设置值。
Keys 获取所有键的集合。
Values 获取所有值的集合。

2. Dictionary 类

概念

  • 定义:Dictionary<TKey, TValue> 是 IDictionary<TKey, TValue> 的具体实现类,基于哈希表实现。
  • 特点:
    • 动态扩容,无需预先指定大小。
    • 插入、查找和删除操作的时间复杂度接近 O(1)。
    • 非线程安全(如需线程安全,可使用 ConcurrentDictionary)。
  • 应用场景:需要高效存储和快速查找键值对的场景。

3. 核心区别

IDictionary Dictionary
接口(不能直接实例化) 具体类(可直接实例化)
定义契约,不提供具体实现 提供基于哈希表的高效实现
用于抽象编程(依赖倒置原则) 用于具体实现

例子

创建

要使用 Dictionary<TKey, TValue>,同样需要引入 System.Collections.Generic 命名空间。在创建字典时,需要指定键和值的类型,例如,如果我们希望以字符串作为键,以整数作为值,则创建一个 Dictionary<string, int> 类型的字典。

using System.Collections.Generic;

// 创建一个以字符串作为键,以整数作为值的字典
Dictionary<string, int> ageDict = new Dictionary<string, int>();

初始化

从C# 3.0 之后提供了初始化器,可以初始化Dictionary

Dictionary<string, int> ageDict = new Dictionary<string, int> {
    {"Alice", 25},
    {"Bob", 30},
    {"Charlie", 22}
};

添加元素-方式一

可以使用 Add() 方法向字典中添加键值对。

注意:如果键已经 存在 于字典中,则 Add() 方法将会抛出异常。

// 添加键值对到字典中
ageDict.Add("Alice", 25);
ageDict.Add("Bob", 30);
ageDict.Add("Charlie", 22);

添加元素-方式二

如果我们希望键可以重复,则可以使用索引符号 [] 直接给字典赋值,这样如果键已经存在,则会更新对应的值。

// 直接赋值给字典,如果键已存在,则更新对应的值
ageDict["Alice"] = 26;

访问元素-方式一

可以通过键访问字典中的值。使用索引符号 [键] 来获取对应的值。

注意:如果字典中不存在该键,则会抛出异常。

// 通过键访问字典中的值
int aliceAge = ageDict["Alice"]; // 获取"Alice"对应的值,此处为26

访问元素-方式二

为了避免抛出异常,可以使用 TryGetValue() 方法。

// 使用 TryGetValue() 避免抛出异常
if (ageDict.TryGetValue("Bob", out int bobAge))
{
    Console.WriteLine($"Bob's age: {bobAge}"); // 输出"Bob's age: 30"
}
else
{
    Console.WriteLine("Bob's age not found.");
}

删除元素

可以使用 Remove() 方法根据键从字典中删除元素。

// 删除字典中的键值对
ageDict.Remove("Charlie");

Clear情况元素

Clear() 方法用于清空整个字典,即删除所有键值对。

遍历字典

可以使用 foreach 循环遍历字典中的所有键值对,或者分别遍历键和值。

// 遍历键值对
foreach (var item in ageDict)
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}

// 遍历键
foreach (var key in ageDict.Keys)
{
    Console.WriteLine(key);
}

// 遍历值
foreach (var value in ageDict.Values)
{
    Console.WriteLine(value);
}

常见问题

  1. 键为 null:若 TKey 为引用类型,插入 null 键会抛出 ArgumentNullException。
  2. 重复键:插入重复键会抛出 ArgumentException,可先使用 ContainsKey 检查。
  3. 线程安全:Dictionary 非线程安全,多线程环境下需使用 ConcurrentDictionary。

其他方法

Count

Count属性用于获取字典中键值对的数量。

int count = ageDict.Count; // 获取键值对的数量,此处为2

ContainsKey和ContainsValue

ContainsKey() 方法用于判断字典中是否包含指定的键,返回一个布尔值。

ContainsValue() 方法用于判断字典中是否包含指定的值,返回一个布尔值。

bool hasAlice = ageDict.ContainsKey("Alice"); // 判断字典是否包含键"Alice"
bool hasAge30 = ageDict.ContainsValue(30); // 判断字典是否包含值为30的元素

参考:
https://blog.csdn.net/qq_21484461/article/details/132227303