I am trying to implement extension method for ConcurrentDictionary
that functionally gets the value from dictionary if key exists. If the key does not exists or the condition (in predicate
) fails, it tries to get the value by calling valueFactory
. Below is the method I have written.
public static TValue ConditionalGetOrAdd<TKey, TValue>(
this ConcurrentDictionary<TKey, TValue> dictionary,
TKey key,
Func<TValue, bool> predicate,
Func<TKey, TValue> valueFactory)
{
TValue value = dictionary.GetOrAdd(key, valueFactory);
if (!predicate(value))
{
value = valueFactory(key);
dictionary[key] = value;
}
return value;
}
There are two issues here. I may call valueFactory
twice in case the predicate
returns false. This would be redundant operation. In addition, the entire method is not atomic. If one thread is inside the if
block, the other thread will not wait for it to complete before calling GetOrAdd
or predicate
.
Is it possible to get this accomplished without taking lock on entire dictionary? In my case, the valueFactory
is costly (makes an HTTP request internally), while predicate
is quite cheap. Let me know if you have a solution. I am okay with modifying the entire method if it serves the purpose.