Получить KeyValuePair по ключу из ConcurrentDictionary (за O (1) раз) - PullRequest
1 голос
/ 07 апреля 2020

В соответствии с этим решением ({ ссылка }) я использую ConcurrentDictionary<T,byte> в качестве обходного пути из-за отсутствия ConcurrentHashSet<T>. Тем не менее, я изо всех сил пытаюсь понять, как я могу вернуть оригинал T Key из словаря за O (1) раз.

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

Есть ли способ получить KeyValuePair<K,V> (или даже просто ключ) для записи ConcurrentDictionary<K,V>, дав ей эквивалентный (IEquatable) ключ, не перечисляя его за O (n) время?

Моя проблема возникает из-за того, что объекты, которые я использую в качестве ключей IEquatable<K> друг для друга, но не ReferenceEqual друг для друга. Если myDict.ContainsKey(someEquatable), я хочу получить исходный экземпляр ключа в словаре (а также значение, сохраненное вместе с ним) и выбросить мой текущий (дублированный) экземпляр.

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

Вот метод расширения для добавления значений к ConcurrentDictionary<T, T>, который используется как ConcurrentHashSet<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
1 голос
/ 07 апреля 2020

Я только что понял, что могу просто переключиться с использования ConcurrentDictionary<TKey, byte> на ConcurrentDictionary<TKey, TKey>. Он может иметь более тяжелую площадь, чем байтовое значение (неподтвержденное), но если значение и ключ совпадают, я легко могу получить ключ из значения.

Чтобы распространить его на тех, кто находит это вопрос и кто на самом деле использует «значение», вы можете выбрать для вашего словаря значение ConcurrentDictionary<TKey, Tuple<TKey, TValue> и таким образом получить как исходный ключ, так и значение.

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