.NET C# Dictionary & Hashtable

.NET C# Dictionary & Hashtable

文章目录

  • [.NET C# Dictionary & Hashtable](# Dictionary & Hashtable)
    • [1 Dictionary](#1 Dictionary)
      • [1.1 底层实现](#1.1 底层实现)
      • [1.2 优点](#1.2 优点)
      • [1.3 缺点](#1.3 缺点)
    • [2 Hashtable](#2 Hashtable)
      • [2.1 底层实现](#2.1 底层实现)
      • [2.2 优点](#2.2 优点)
      • [2.3 缺点](#2.3 缺点)
    • [3 对比总结](#3 对比总结)
    • [4 遍历方式,与耗时对比](#4 遍历方式,与耗时对比)

1 Dictionary

1.1 底层实现

  • 哈希表Dictionary 底层实现是一个哈希表。它使用键的哈希值来快速定位值。
  • 泛型支持Dictionary<TKey, TValue> 是泛型的,可以存储任何类型的键和值,这增加了类型安全性。
  • 存储结构:内部使用一个数组来存储键值对,并通过哈希函数计算每个键的哈希值,将其映射到数组中的一个索引位置。

1.2 优点

  • 类型安全:由于是泛型,编译时可以检查类型,避免了类型转换错误。
  • 性能:查找、插入和删除操作的平均时间复杂度为 O(1),非常高效。
  • 灵活性:可以存储任何类型的键和值,使用方便。

1.3 缺点

  • 内存消耗:由于使用泛型和哈希表,内存消耗相对较大。
  • 初始化时间:初始化和重新调整大小时可能会有较大的时间开销。

2 Hashtable

2.1 底层实现

  • 哈希表Hashtable 也使用哈希表来实现。
  • 非泛型Hashtable 是非泛型的,键和值都是 object 类型,需要进行装箱和拆箱操作。

2.2 优点

  • 灵活性:可以存储任何类型的键和值,但需要进行类型转换。
  • 历史悠久:在 .NET 1.0 中就存在,兼容旧版本代码。

2.3 缺点

  • 类型不安全 :由于键和值都是 object 类型,编译时无法检查类型,容易出错。
  • 性能较差 :由于需要装箱和拆箱,性能不如 Dictionary
  • 过时 :随着泛型集合的引入,Hashtable 已经不再推荐使用。

3 对比总结

  1. 类型安全性Dictionary 是泛型的,更加类型安全,而 Hashtable 是非泛型的,需要进行类型转换。
  2. 性能Dictionary 性能优于 Hashtable,特别是在涉及大量数据操作时。
  3. 内存消耗Dictionary 由于泛型和哈希表的实现,内存消耗较大,而 Hashtable 相对较小,但性能不如前者。
  4. 历史兼容性Hashtable 由于存在时间较长,在一些旧项目中仍然可以见到,但新的项目一般推荐使用 Dictionary

4 遍历方式,与耗时对比

foreach遍历

csharp 复制代码
foreach (DictionaryEntry entry in hashtable)
{
    var key = entry.Key;
    var value = entry.Value;
}

foreach (KeyValuePair<int,int> entry in dictionary)
{
    var key = entry.Key;
    var value = entry.Value;
}

Keys遍历

csharp 复制代码
foreach (var key in hashtable.Keys)
{
    var value = hashtable[key];
}

foreach (var key in dictionary.Keys)
{
    var value = dictionary[key];
}

IDictionaryEnumerator遍历

csharp 复制代码
IDictionaryEnumerator enumeratorHt = hashtable.GetEnumerator();
while (enumeratorHt.MoveNext())
{
    var key = enumeratorHt.Key;
    var value = enumeratorHt.Value;
}

IDictionaryEnumerator enumeratorDic = dictionary.GetEnumerator();
while (enumeratorDic.MoveNext())
{
    var key = enumeratorDic.Key;
    var value = enumeratorDic.Value;
}

耗时对比

csharp 复制代码
static void Main(string[] args)
{
    // 创建并填充Hashtable
    Hashtable hashtable = new Hashtable();
    Dictionary<int,int> dictionary = new Dictionary<int,int>();
    for (int i = 0; i < 10000000; i++)
    {
        hashtable[i] = i;
        dictionary[i] = i;
    }

    // 基准测试
    Stopwatch stopwatch = new Stopwatch();

    // 测试foreach遍历
    stopwatch.Start();
    foreach (DictionaryEntry entry in hashtable)
    {
        var key = entry.Key;
        var value = entry.Value;
    }
    stopwatch.Stop();
    Console.WriteLine($"Hashtable - foreach遍历耗时: {stopwatch.ElapsedMilliseconds} 毫秒");

    stopwatch.Restart();
    stopwatch.Start();
    foreach (KeyValuePair<int,int> entry in dictionary)
    {
        var key = entry.Key;
        var value = entry.Value;
    }
    stopwatch.Stop();
    Console.WriteLine($"Dictionary - foreach遍历耗时: {stopwatch.ElapsedMilliseconds} 毫秒");

    // 测试Keys遍历
    stopwatch.Restart();
    foreach (var key in hashtable.Keys)
    {
        var value = hashtable[key];
    }
    stopwatch.Stop();
    Console.WriteLine($"Hashtable - Keys遍历耗时: {stopwatch.ElapsedMilliseconds} 毫秒");

    stopwatch.Restart();
    foreach (var key in dictionary.Keys)
    {
        var value = dictionary[key];
    }
    stopwatch.Stop();
    Console.WriteLine($"Dictionary - Keys遍历耗时: {stopwatch.ElapsedMilliseconds} 毫秒");

    // 测试IDictionaryEnumerator遍历
    stopwatch.Restart();
    IDictionaryEnumerator enumeratorHt = hashtable.GetEnumerator();
    while (enumeratorHt.MoveNext())
    {
        var key = enumeratorHt.Key;
        var value = enumeratorHt.Value;
    }
    stopwatch.Stop();
    Console.WriteLine($"Hashtable - IDictionaryEnumerator遍历耗时: {stopwatch.ElapsedMilliseconds} 毫秒");

    stopwatch.Restart();
    IDictionaryEnumerator enumeratorDic = dictionary.GetEnumerator();
    while (enumeratorDic.MoveNext())
    {
        var key = enumeratorDic.Key;
        var value = enumeratorDic.Value;
    }
    stopwatch.Stop();
    Console.WriteLine($"Dictionary - IDictionaryEnumerator遍历耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
}

输出:

Hashtable - foreach遍历耗时: 576 毫秒

Dictionary - foreach遍历耗时: 93 毫秒

Hashtable - Keys遍历耗时: 279 毫秒

Dictionary - Keys遍历耗时: 112 毫秒

Hashtable - IDictionaryEnumerator遍历耗时: 147 毫秒

Hashtable - foreach遍历耗时: 576 毫秒

Dictionary - foreach遍历耗时: 93 毫秒

Hashtable - Keys遍历耗时: 279 毫秒

Dictionary - Keys遍历耗时: 112 毫秒

Hashtable - IDictionaryEnumerator遍历耗时: 147 毫秒

Dictionary - IDictionaryEnumerator遍历耗时: 169 毫秒

相关推荐
weixin_307779134 分钟前
使用C#实现从Hive的CREATE TABLE语句中提取分区字段名和数据类型
开发语言·数据仓库·hive·c#
时光追逐者1 小时前
在 Blazor 中使用 Chart.js 快速创建数据可视化图表
开发语言·javascript·信息可视化·c#·.net·blazor
与火星的孩子对话2 小时前
Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
人工智能·unity·c#·游戏引擎·语音识别·宠物
response_L2 小时前
国产系统统信uos和麒麟v10在线打开word给表格赋值
java·c#·word·信创·在线编辑
MasterNeverDown2 小时前
Swagger2Md:让WebAPI文档生成变得轻松高效
c#
向宇it2 小时前
【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍
开发语言·游戏·unity·c#·编辑器·游戏引擎
三天不学习2 小时前
Lucene.Net FSDirectory 和 RAMDirectory 的区别和用法 【搜索引擎系列教程】
搜索引擎·.net·lucene
爱的叹息9 小时前
RedisTemplate 的 6 个可配置序列化器属性对比
算法·哈希算法
闪电麦坤9511 小时前
C#:base 关键字
开发语言·c#
mingupup12 小时前
C#连接小智服务器并将音频解码播放过程记录
c#