商城首页欢迎来到中国正版软件门户

您的位置:首页 >c#如何遍历字典中的key和value_c#遍历字典key和value详解

c#如何遍历字典中的key和value_c#遍历字典key和value详解

  发布于2026-05-03 阅读(0)

扫一扫,手机访问

遍历字典的Key和Value:安全、高效与那些容易踩的坑

c#如何遍历字典中的key和value_c#遍历字典key和value详解

在C#中处理Dictionary时,遍历操作几乎是家常便饭。但方法选不对,轻则性能受损,重则直接抛出异常。简单来说,最稳妥的路径是直接用foreach遍历KeyValuePair;而单独遍历KeysValues属性,不仅会丢失键值关联,还可能在不经意间引发并发修改问题。

首选方案:用 foreach 遍历 KeyValuePair

这是最经典也最推荐的方式。它能在一次迭代中同时获取键和值,既避免了重复查找的开销,也天然规避了在遍历过程中修改字典可能导致的InvalidOperationException——当然,前提是你没有真的在循环体内去改动它。

来看一个标准示例:

var dict = new Dictionary { ["a"] = 1, ["b"] = 2 };
foreach (var kvp in dict)
{
    Console.WriteLine($"{kvp.Key} -> {kvp.Value}");
}

这里有个细节值得注意:循环变量kvp的类型是KeyValuePair,它并非一个匿名元组。因此,你不能直接使用C# 7+的元组解构语法写成var (key, value),而必须显式地访问kvp.Keykvp.Value

关于解构语法:需要一点额外转换

如果你偏爱var (key, value)这种简洁的解构写法,确实有办法实现,但需要绕个小弯。Dictionary的枚举器返回的是KeyValuePair,不是元组,所以得先转换一下。

  • 一种常见做法是使用LINQ:dict.Select(kvp => (kvp.Key, kvp.Value))。这会将序列转换为匿名元组。不过,这引入了LINQ的延迟执行机制,并且每次访问都会创建一个新的元组对象,带来微小的性能开销。
  • 也可以结合AsEnumerable()Select来实现,思路类似。
  • 话说回来,如果只是为了写法上的简洁,很多时候直接使用kvp.Keykvp.Value反而是更优选择——它更直接、性能更好,而且避免了不必要的装箱操作。

一个必须警惕的陷阱:遍历时修改字典

这是新手甚至老手都容易翻车的地方。当Dictionary正在被foreach遍历时,如果在循环体内直接调用AddRemoveClear等方法,运行时将立刻抛出InvalidOperationException,并提示“Collection was modified”。

  • 需要边遍历边删除怎么办? 安全的做法是先收集需要删除的键,遍历结束后再统一处理。例如:var keysToRemove = dict.Where(x => x.Value < 0).Select(x => x.Key).ToList(); keysToRemove.ForEach(dict.Remove);
  • 需要边遍历边添加呢? 建议使用一个新的字典来承接要添加的项,或者可以考虑改用for循环配合dict.Keys.ToList()(注意,ToList()会复制一份键的集合,会增加一些内存消耗)。
  • 多线程环境呢? 即使只是进行只读遍历,在并发环境下使用普通的Dictionary也可能遇到迭代器状态不可预测的问题。这时,ConcurrentDictionary才是正确的选择。

Keys 和 Values 属性:只适合特定场景

dict.Keysdict.Values返回的是字典键或值的只读视图。单独遍历它们本身没有问题,但需要注意两点:一是文档并未承诺其遍历顺序与另一侧完全一致(尽管当前实现通常是稳定的);二是它们只提供了单侧信息。

  • 当你只需要处理所有的键时(比如检查是否存在某个特定前缀),使用foreach (var key in dict.Keys)是完全合适的。
  • 但如果你需要根据键来获取值,却选择先遍历Keys,再在循环内通过dict[key]查找,那性能就比不上直接遍历KeyValuePair了。因为每次dict[key]都是一次哈希查找,有开销,并且如果键不存在还会引发KeyNotFoundException
  • 遍历Values时同理:你完全丢失了键的上下文,无法进行反向查找,也不适用于需要键值配对的逻辑。

还有一个容易被忽略的关键点:在标准的Dictionary中,遍历顺序并不等于插入顺序(即使在.NET Core 2.0+和.NET 5+中,默认行为也是如此)。如果你需要按插入顺序或特定顺序进行遍历,应当选择SortedDictionaryImmutableSortedDictionary,或者自己维护一个List来保证顺序。

本文转载于:https://www.php.cn/faq/2324784.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注