暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

C# 字典(Dictionary)全面解析及实践示例

技术老小子 2025-03-11
17

本教程是C#的入门学习教程,我尽量找时间写全它,预计每周不少于3篇吧,但由于不是专业搞课程的,只能是尽力而为,希望对你入门有所帮助。

在 C# 开发中,Dictionary<TKey, TValue>
(简称 Dictionary)是一种非常常用且高效的数据结构。它也可以帮助我们快速访问、管理大量的键值对。在本文中,我们将结合示例详细介绍 Dictionary 的使用场景、常用操作以及最佳实践,帮助你更好地理解 C# 字典在实际业务中的运用。如果你了解JSON就对它了解了,可以说,这个是现在NOSQL的根了。


什么是 C# Dictionary

Dictionary<TKey, TValue>
 是 C# 基础类库中提供的泛型集合类型,用于存储键值对(Key-Value pair)。

  • Key(键)
    :具有唯一性,如果插入重复键,会抛出异常或覆盖视具体情况而定。
  • Value(值)
    :可以重复,不限制唯一性。

Dictionary 的特点 

  1. 快速查找  

    Dictionary 使用哈希表(Hash Table)实现,能提供平均 O(1) 的查找速度,也就是说,随着元素数量的增多,其访问效率依然较为稳定和高效。

  2. 无序集合  

    Dictionary 中元素存储顺序并不一定与插入顺序一致,无法按照加入的顺序来遍历获取,需要注意这一点。

  3. 泛型支持  

    Dictionary<TKey, TValue>
     支持指定键和值的数据类型,能更好地利用类型安全。

  4. 应用场景广  

    • 缓存系统的存储:根据唯一标识(Key)快速检索对象。  
    • 数据统计:用键来表示一个标识或名称,值用于存储统计结果或其他信息。  
    • 快速查找表:需要在海量数据中快速定位时,非常适用。  
    • 配置管理:常用来加载配置项,按键快速检索。

Dictionary 常用操作

以下为 Dictionary 中常见的方法和属性:

  1. Add(TKey key, TValue value)  

    添加新的键值对。若键已存在,会抛出异常。

  2. Remove(TKey key)  

    根据键删除对应的键值对。

  3. ContainsKey(TKey key)  

    判断字典中是否包含指定键。

  4. ContainsValue(TValue value)  

    判断字典中是否包含指定值。

  5. TryGetValue(TKey key, out TValue value)  

    尝试获取与指定键关联的值,避免在键不存在时发生异常。

  6. this[TKey key](索引器)  

    获取或设置与指定键相关联的值。但若键不存在,直接访问会抛出异常,因此推荐配合 TryGetValue()
     使用。

示例:添加、访问和删除操作 

using System;
using System.Collections.Generic;

namespace AppDictionary
{
    internal class Program
    {

        static void Main(string[] args)
        
{
            // 1. 创建一个 Dictionary,键为 string,值为 int
            Dictionary<stringint> ages = new Dictionary<stringint>();

            // 2. 使用 Add 方法添加键值对
            ages.Add("Alice"30);
            ages.Add("Bob"25);

            // 3. 通过索引器方式添加或修改数据
            ages["Charlie"] = 28;

            // 4. 遍历字典中的所有键值对
            foreach (KeyValuePair<stringint> kvp in ages)
            {
                Console.WriteLine($"Name: {kvp.Key}, Age: {kvp.Value}");
            }

            // 5. 检查字典中是否包含某个键
            if (ages.ContainsKey("Alice"))
            {
                Console.WriteLine("找到 Alice,Age = " + ages["Alice"]);
            }

            // 6. 使用 TryGetValue 方法安全地获取值
            if (ages.TryGetValue("Bob", out int bobAge))
            {
                Console.WriteLine("找到 Bob,Age = " + bobAge);
            }

            // 7. 使用 Remove 方法移除键值对
            ages.Remove("Charlie");

            // 移除后再次检查
            if (!ages.ContainsKey("Charlie"))
            {
                Console.WriteLine("Charlie 已从字典中移除");
            }
        }
    }
}

复制

结合 LINQ 的 Dictionary 查询示例

在 C# 中,结合 LINQ(Language Integrated Query)可以更灵活地对 Dictionary 进行查询和操作。下面示例展示了如何在字典里使用 LINQ 筛选出符合条件的项目,并倒序排列它们的值。

using System;
using System.Collections.Generic;
using System.Linq;

namespace AppDictionary
{
    internal class Program
    {

        static void Main(string[] args)
        
{
            // Dictionary 初始化
            Dictionary<stringint> scores = new Dictionary<stringint>()
            {
                {"Alice"95},
                {"Bob"80},
                {"Charlie"85},
                {"David"90}
            };

            // 查找分数大于 85 的学生,并按照分数倒序
            var highScores = scores.Where(kvp => kvp.Value > 85)
                                   .OrderByDescending(kvp => kvp.Value);

            Console.WriteLine("High Scores:");
            foreach (var score in highScores)
            {
                Console.WriteLine($"{score.Key}: {score.Value}");
            }

            // 转换为新的映射关系:成绩转化为 A、B、C
            Dictionary<stringstring> gradeMap =
                scores.ToDictionary(
                    kvp => kvp.Key,
                    kvp => kvp.Value >= 90 ? "A" : kvp.Value >= 80 ? "B" : "C"
                );

            Console.WriteLine("Grade Map:");
            foreach (var item in gradeMap)
            {
                Console.WriteLine($"{item.Key}: {item.Value}");
            }
        }
    }
}

复制

在实际开发中,配合 LINQ 能够大幅度提高数据处理的可读性和开发效率,无论是进行过滤、排序还是进行数据转换都非常方便。


使用字典实现单词统计

Dictionary 非常适合做数据统计的场景,例如:统计文本中每个单词出现的次数。

using System;
using System.Collections.Generic;

namespace AppDictionary
{
    internal class Program
    {

        static void Main(string[] args)
        
{
            string text = "the quick brown fox jumps over the lazy dog";
            Dictionary<stringint> wordCount = new Dictionary<stringint>();

            // 分割文本并统计每个单词出现的次数
            foreach (string word in text.Split(' '))
            {
                if (wordCount.ContainsKey(word))
                {
                    wordCount[word]++;
                }
                else
                {
                    wordCount[word] = 1;
                }
            }

            // 输出统计结果
            foreach (var item in wordCount)
            {
                Console.WriteLine($"单词 '{item.Key}' 出现了 {item.Value} 次");
            }
        }
    }
}

复制

利用 Dictionary 实现简单缓存

在一些场景下,为了防止重复计算,可以使用 Dictionary 作为简单的缓存容器。下面演示用 GetOrAdd
 方法完成缓存逻辑的思路:

using System;
using System.Collections.Generic;

namespace AppDictionary
{
    internal class Program
    {

        static void Main(string[] args)
        
{
            var cache = new SimpleCache<stringint>();

            // 第一次访问时,值不存在,需要调用工厂方法计算
            int value = cache.GetOrAdd("key1", k => 100);
            Console.WriteLine(value);  

            // 第二次访问同一个键,直接从缓存返回,无需重新计算
            int sameValue = cache.GetOrAdd("key1", k => 200);
            Console.WriteLine(sameValue); 
        }
    }

    publicclass SimpleCache<TKey, TValue>
    {

        private Dictionary<TKey, TValue> _cache = new Dictionary<TKey, TValue>();

        public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
        
{
            if (!_cache.TryGetValue(key, out TValue value))
            {
                value = valueFactory(key);
                _cache[key] = value;
            }

            return value;
        }

        public void Remove(TKey key)
        
{
            _cache.Remove(key);
        }
    }
}

复制

上例展示了通过 TryGetValue
 来检查缓存中是否已存在对应 Key 的值,如果不存在则使用 委托 去生成并存储,再返回给调用方。


实用场景与最佳实践

  1. 使用 TryGetValue
     代替索引器
      

    尽量使用 TryGetValue(key, out value)
     来获取值,避免出现 KeyNotFoundException
     异常。

  2. 考虑并发安全  

    在多线程环境下使用 Dictionary
     时,请考虑线程安全问题。可以使用 lock
     机制或使用线程安全版本的 ConcurrentDictionary<TKey, TValue>

  3. 及时释放或移除无用数据  

    Dictionary 无法自动清理,若要防止内存浪费,应及时调用 Remove
     或重新初始化字典。

  4. 合理设置容量  

    如果已经知道字典大致存储多少条(如数百万级),可以在初始化时为 Dictionary 提供容量参数,减少后续扩容带来的性能开销。

  5. 应用在高频检索场景  

    例如:

    • 频繁访问某些表配置信息。  
    • 实现对象或数据缓存。  
    • 快速根据 ID 查找对象。  
    • 实现简单的路由或者映射关系。
  6. 注意内存占用  

    对于超大规模数据(如上百万级别),需要权衡内存开销与检索效率之间的平衡,合理使用数据结构及数据库或其它缓存。


总结

在 C# 开发中,Dictionary<TKey, TValue>
 提供了快速查找、灵活存储和高效管理的特性,是构建许多功能性模块(如缓存系统、统计表、设置管理等)的核心工具。

通过本文你可以了解到:

  • Dictionary 的基本特性和使用方法  
  • 结合 LINQ 在字典中灵活查询、转换及排序  
  • 用字典进行数据统计和简单缓存的业务实践  
  • 实际开发中的使用注意事项与最佳实践  

无论是在处理少量数据还是大量数据时,只要场景需要快速查找或键值映射,Dictionary
 都能有效提升程序的可维护性和性能。结合本文提供的诸多示例,你可以在实际项目中更加得心应手地使用 C# 的字典结构来解决问题。祝你编程愉快!


如果你正在从事上位机、自动化、机器视觉、物联网(IOT)项目或数字化转型方面的工作,欢迎加入我的微信圈子!在这里,我们不仅可以轻松畅聊最新技术动态和行业趋势,还能够在技术问题上互相帮助和支持。我会尽量利用我的知识和经验来帮助你解决问题,当然也期待从大家的专业见解中学习和成长。无论你是新手还是老鸟,期待与志同道合的朋友交流心得,一起进步!

文章转载自技术老小子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论