从 ConcurrentDictionary 按键获取 KeyValuePair(在 O(1) 时间内)

Get KeyValuePair by Key from a ConcurrentDictionary (in O(1) time)

根据此解决方案 (),我使用 ConcurrentDictionary<T,byte> 作为缺少 ConcurrentHashSet<T> 的解决方法。但是,我正在努力了解如何在 O(1) 时间内从字典中取出原来的 T Key

var cache = new ConcurrentDictionary<MyEquatableClass, byte>());
//...
if(!cache.TryAdd(classInstance, Byte.MinValue))
    return /* Existing cache entry */;
return classInstance;

有什么方法可以通过给 ConcurrentDictionary<K,V> 条目一个等效的(IEquatable)键来获取 KeyValuePair<K,V> (甚至只是键),而不用在 O(n ) 时间?

我的问题出现是因为我用作键的对象是彼此 IEquatable<K>,而不是彼此 ReferenceEqual。如果myDict.ContainsKey(someEquatable),我想获取字典中的原始键实例(以及与其存储的值),并丢弃我当前(重复)的实例。

我刚刚意识到我可以从使用 ConcurrentDictionary<TKey, byte> 切换到 ConcurrentDictionary<TKey, TKey>。它可能比字节值(未确认)占用更多空间,但如果值和密钥相同,我可以轻松地从值中获取密钥。

为了将此扩展到那些发现这个问题和实际使用 "value" 的人,您可以选择将字典更改为 ConcurrentDictionary<TKey, Tuple<TKey, TValue>,并同时获取原始键和对应的值方式。

var cache = new ConcurrentDictionary<MyEquatableClass, MyEquatableClass>());
//...
if(!cache.TryAdd(classInstance, classInstance))
    return cache[classInstance];
return classInstance;

这是一个扩展方法,用于将值添加到用作 ConcurrentHashSet<T>ConcurrentDictionary<T, T>(具有等于键的值):

/// <summary>
/// Adds a value to a <see cref="ConcurrentDictionary{T,T}"/>
/// used as a concurrent <see cref="HashSet{T}"/>, if it does not already exist.<br/>
/// Returns the new value, or the existing value if the value exists.
/// </summary>
/// <param name="value">The value to be added, if it does not already exist.</param>
public static T GetOrAdd<T>(this ConcurrentDictionary<T, T> source, T value)
{
    return source.GetOrAdd(value, value);
}

用法示例:

var dict = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Console.WriteLine($"dict.GetOrAdd(\"abc\"): {dict.GetOrAdd("abc")}");
Console.WriteLine($"dict.GetOrAdd(\"ABC\"): {dict.GetOrAdd("ABC")}");
Console.WriteLine($"dict.Count: {dict.Count}");

输出:

dict.GetOrAdd("abc"): abc
dict.GetOrAdd("ABC"): abc
dict.Count: 1