如何实现Dictionary<TKey,TValue>的TryGetKey功能?
在Dictionary中高效获取实际存储的键
问题背景
我需要在使用忽略大小写比较器的Dictionary<string, string>中,获取字典实际存储的键(比如传入小写的"ch",要拿到字典里的"CH"),类似HashSet<TKey>.TryGetValue的功能,但Dictionary<TKey, TValue>.TryGetValue只能返回对应的值,无法拿到原始键。同时我不想通过遍历所有键值对来实现,希望有高效的方案。
示例场景:
Dictionary<string, string > _countryNames = new(StringComparer.OrdinalIgnoreCase) { {"CH", "Switzerland"}, {"DE", "Germany"}, {"US", "USA"} }; // 传入"ch",期望返回"CH" string GetValidIsoCountry(string countryCode) { if (!_countryNames.ContainsKey(countryCode)) { return null; } // 此处需要获取实际存储的键,而非传入的countryCode }
高效解决方案
方法1:使用.NET 6+的CollectionsMarshal(推荐)
利用System.Runtime.InteropServices.CollectionsMarshal提供的GetDictionaryEntryRefOrNullRef方法,直接访问字典内部的哈希桶,无需遍历即可定位到目标键值对,效率和TryGetValue一致。
using System.Runtime.InteropServices; using System.Runtime.CompilerServices; public static class DictionaryExtensions { public static bool TryGetActualKey<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, out TKey actualKey) { if (dictionary == null) throw new ArgumentNullException(nameof(dictionary)); // 获取对应键值对的引用,不存在则返回空引用 ref var entry = ref CollectionsMarshal.GetDictionaryEntryRefOrNullRef(dictionary, key); if (!Unsafe.IsNullRef(ref entry)) { actualKey = entry.Key; return true; } actualKey = default; return false; } }
使用示例:
string GetValidIsoCountry(string countryCode) { if (_countryNames.TryGetActualKey(countryCode, out string actualCode)) { return actualCode; } return null; }
方法2:维护配套的HashSet(兼容旧版本.NET)
如果你的项目使用的是.NET Framework或低版本.NET Core,可以同时维护一个和字典键对应的HashSet<string>,利用HashSet.TryGetValue获取实际键,逻辑简单且高效。
HashSet<string> _validCountryCodes = new(StringComparer.OrdinalIgnoreCase) { "CH", "DE", "US" }; Dictionary<string, string > _countryNames = new(StringComparer.OrdinalIgnoreCase) { {"CH", "Switzerland"}, {"DE", "Germany"}, {"US", "USA"} }; string GetValidIsoCountry(string countryCode) { if (_validCountryCodes.TryGetValue(countryCode, out string actualCode)) { return actualCode; } return null; }
方法3:自定义字典类(适合小体量字典)
如果字典数据量不大,可以封装自定义字典类,直接提供获取实际键的方法,缺点是内部需要遍历键值对,效率较低。
public class DictionaryWithActualKey<TKey, TValue> : Dictionary<TKey, TValue> { public DictionaryWithActualKey(IEqualityComparer<TKey> comparer) : base(comparer) { } public bool TryGetActualKey(TKey key, out TKey actualKey) { foreach (var kvp in this) { if (Comparer.Equals(kvp.Key, key)) { actualKey = kvp.Key; return true; } } actualKey = default; return false; } }
内容的提问来源于stack exchange,提问作者Tim Schmelter
相关产品推荐
相关产品推荐

