316 lines
6.1 KiB
Markdown
316 lines
6.1 KiB
Markdown
|
|
# Hashtable
|
|||
|
|
概念:
|
|||
|
|
`Hashtable` 是 C# 提供的一个==非泛型键值对集合==
|
|||
|
|
它通过键 `key` 来查找值 `value`
|
|||
|
|
|
|||
|
|
简单理解:
|
|||
|
|
像一本字典
|
|||
|
|
用“词”查“解释”
|
|||
|
|
用 `key` 查 `value`
|
|||
|
|
|
|||
|
|
命名空间:
|
|||
|
|
```csharp
|
|||
|
|
using System.Collections;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 通常用法
|
|||
|
|
1. 保存键值对数据
|
|||
|
|
2. 通过唯一键快速查找对应值
|
|||
|
|
3. 学习哈希表这种数据结构
|
|||
|
|
4. 理解 `Dictionary<TKey, TValue>` 之前的非泛型写法
|
|||
|
|
|
|||
|
|
实际开发中:
|
|||
|
|
新代码更推荐使用 `Dictionary<TKey, TValue>`
|
|||
|
|
`Hashtable` 主要用于学习非泛型键值对集合
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 语法
|
|||
|
|
创建:
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
添加:
|
|||
|
|
```csharp
|
|||
|
|
table.Add(键, 值);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
通过键取值:
|
|||
|
|
```csharp
|
|||
|
|
object value = table[键];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
修改:
|
|||
|
|
```csharp
|
|||
|
|
table[键] = 新值;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
数量:
|
|||
|
|
```csharp
|
|||
|
|
table.Count
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 基础案例
|
|||
|
|
```csharp
|
|||
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
|
|||
|
|
table.Add("name", "小明");
|
|||
|
|
table.Add("age", 18);
|
|||
|
|
table.Add("isVip", true);
|
|||
|
|
|
|||
|
|
Console.WriteLine(table["name"]);
|
|||
|
|
Console.WriteLine(table["age"]);
|
|||
|
|
Console.WriteLine(table["isVip"]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
理解:
|
|||
|
|
1. `"name"`、`"age"`、`"isVip"` 是键
|
|||
|
|
2. `"小明"`、`18`、`true` 是值
|
|||
|
|
3. 通过键可以找到对应的值
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# Add 和索引器
|
|||
|
|
使用 `Add` 添加:
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
|
|||
|
|
table.Add("id", 1001);
|
|||
|
|
table.Add("name", "小明");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
使用索引器添加或修改:
|
|||
|
|
```csharp
|
|||
|
|
table["score"] = 90; // 如果 key 不存在,就是新增
|
|||
|
|
table["score"] = 100; // 如果 key 已存在,就是修改
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
区别:
|
|||
|
|
1. `Add` 遇到重复键会报错
|
|||
|
|
2. `table[key] = value` 遇到重复键会覆盖旧值
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 增删查改
|
|||
|
|
增加:
|
|||
|
|
```csharp
|
|||
|
|
table.Add("level", 10);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
删除:
|
|||
|
|
```csharp
|
|||
|
|
table.Remove("level");
|
|||
|
|
table.Clear();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
查找键:
|
|||
|
|
```csharp
|
|||
|
|
bool hasName = table.ContainsKey("name");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
查找值:
|
|||
|
|
```csharp
|
|||
|
|
bool hasValue = table.ContainsValue("小明");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
修改:
|
|||
|
|
```csharp
|
|||
|
|
table["name"] = "小红";
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
取值:
|
|||
|
|
```csharp
|
|||
|
|
string name = (string)table["name"];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 遍历
|
|||
|
|
遍历键值对:
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
|
|||
|
|
table.Add("name", "小明");
|
|||
|
|
table.Add("age", 18);
|
|||
|
|
|
|||
|
|
foreach (DictionaryEntry item in table)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine(item.Key + " : " + item.Value);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
只遍历键:
|
|||
|
|
```csharp
|
|||
|
|
foreach (object key in table.Keys)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine(key);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
只遍历值:
|
|||
|
|
```csharp
|
|||
|
|
foreach (object value in table.Values)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine(value);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
注意:
|
|||
|
|
`Hashtable` 的遍历顺序不保证等于添加顺序
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# key 不能重复
|
|||
|
|
错误写法:
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
|
|||
|
|
table.Add("name", "小明");
|
|||
|
|
table.Add("name", "小红");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
`Hashtable` 中的 key 必须唯一
|
|||
|
|
重复添加同一个 key 会报错
|
|||
|
|
|
|||
|
|
如果想修改旧值:
|
|||
|
|
```csharp
|
|||
|
|
table["name"] = "小红";
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# key 不能是 null
|
|||
|
|
错误写法:
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
|
|||
|
|
table.Add(null, "值");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
`Hashtable` 的 key 不能为 `null`
|
|||
|
|
|
|||
|
|
但是 value 可以是 `null`:
|
|||
|
|
```csharp
|
|||
|
|
table.Add("data", null);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 取值时要判断 key 是否存在
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
table.Add("name", "小明");
|
|||
|
|
|
|||
|
|
if (table.ContainsKey("name"))
|
|||
|
|
{
|
|||
|
|
string name = (string)table["name"];
|
|||
|
|
Console.WriteLine(name);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
为什么要判断:
|
|||
|
|
1. key 不存在时,`table[key]` 可能拿到 `null`
|
|||
|
|
2. value 本身也可能是 `null`
|
|||
|
|
3. 用 `ContainsKey` 可以区分“没有这个键”和“这个键的值是 null”
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 取值时要类型转换
|
|||
|
|
```csharp
|
|||
|
|
Hashtable table = new Hashtable();
|
|||
|
|
table.Add("age", 18);
|
|||
|
|
|
|||
|
|
int age = (int)table["age"];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
非泛型 `Hashtable` 的 key 和 value 都是按 `object` 处理
|
|||
|
|
取出来后通常需要强制类型转换
|
|||
|
|
|
|||
|
|
如果类型转错:
|
|||
|
|
```csharp
|
|||
|
|
string age = (string)table["age"];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
会出错,因为 `"age"` 对应的值实际是 `int`。
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 和 ArrayList 的区别
|
|||
|
|
| 对比点 | ArrayList | Hashtable |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 存储方式 | 单个元素 | 键值对 |
|
|||
|
|
| 访问方式 | 通过下标 | 通过 key |
|
|||
|
|
| key 是否存在 | 没有 key | key 必须唯一 |
|
|||
|
|
| 常见用途 | 普通列表 | 字典式查找 |
|
|||
|
|
| 泛型替代 | `List<T>` | `Dictionary<TKey, TValue>` |
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 常见错误
|
|||
|
|
错误1:重复 Add 同一个 key
|
|||
|
|
```csharp
|
|||
|
|
table.Add("id", 1);
|
|||
|
|
table.Add("id", 2);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
应该改成:
|
|||
|
|
```csharp
|
|||
|
|
table["id"] = 2;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
错误2:以为 Hashtable 有添加顺序
|
|||
|
|
|
|||
|
|
实际:
|
|||
|
|
`Hashtable` 是根据 key 的哈希来组织数据
|
|||
|
|
遍历顺序不保证是添加顺序
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
错误3:取值后忘记强转
|
|||
|
|
```csharp
|
|||
|
|
int age = table["age"];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
应该写:
|
|||
|
|
```csharp
|
|||
|
|
int age = (int)table["age"];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 注意
|
|||
|
|
1. `Hashtable` 在 `System.Collections` 命名空间中
|
|||
|
|
2. `Hashtable` 是非泛型键值对集合
|
|||
|
|
3. key 不能重复
|
|||
|
|
4. key 不能是 `null`
|
|||
|
|
5. value 可以是 `null`
|
|||
|
|
6. `Add` 重复 key 会报错
|
|||
|
|
7. `table[key] = value` 可以新增,也可以覆盖旧值
|
|||
|
|
8. 遍历顺序不保证等于添加顺序
|
|||
|
|
9. 新项目通常优先使用 `Dictionary<TKey, TValue>`
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 一句话记忆
|
|||
|
|
==Hashtable 是用 key 找 value 的非泛型键值对集合。==
|
|||
|
|
|
|||
|
|
再压缩一点:
|
|||
|
|
==ArrayList 靠下标找,Hashtable 靠 key 找。==
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
# 面试/复习时怎么说
|
|||
|
|
可以这样答:
|
|||
|
|
|
|||
|
|
“Hashtable 是 `System.Collections` 命名空间下的非泛型键值对集合,通过唯一 key 查找 value。
|
|||
|
|
它的 key 不能重复,也不能为 null;value 可以为 null。
|
|||
|
|
因为 key 和 value 都按 object 处理,所以取值时通常需要强制类型转换。新项目中一般更推荐使用泛型集合 `Dictionary<TKey, TValue>`。”
|
|||
|
|
|
|||
|
|
----
|
|||
|
|
引用:
|
|||
|
|
1. Microsoft Learn: [Hashtable Class](https://learn.microsoft.com/dotnet/api/system.collections.hashtable?view=net-9.0)
|
|||
|
|
2. Microsoft Learn: [Hashtable.Add Method](https://learn.microsoft.com/en-us/dotnet/api/system.collections.hashtable.add?view=net-9.0)
|
|||
|
|
3. Microsoft Learn: [Hashtable.Item Property](https://learn.microsoft.com/en-us/dotnet/api/system.collections.hashtable.item?view=net-9.0)
|
|||
|
|
4. Microsoft Learn: [System.Collections Namespace](https://learn.microsoft.com/en-us/dotnet/api/system.collections?view=net-9.0)
|
|||
|
|
|
|||
|
|
#Hashtable
|
|||
|
|
#哈希表
|
|||
|
|
#集合
|
|||
|
|
#进阶
|