I have a simple scenario where I want to update the value of an existing item. Only AddOrUpdate method offers a delegate where I can update the old value. However I don't want to add anything if the key does not exist. Also TryUpdate method has no overloads that I can get the old value. Is there a way to do it with current API?
Here's the signature I am looking for:
bool TryUpdate(TKey key, Func<TValue,TValue> updateValueFactory)
You have to be prepared to loop and perhaps call the Func
more than once (the same as with the overload of GetOrAdd
that uses one). This means that if the Func
has side-effects, it will not appear to be atomic from the outside. Really, Func
s shouldn't have side-effects, but they always have some cost so the possibility of repeat calls can't be ignored:
public static bool TryUpdate<TKey, TValue>(
this ConcurrentDictionary<TKey, TValue> dict,
TKey key,
Func<TValue, TValue> updateFactory)
{
TValue curValue;
while(dict.TryGetValue(key, out curValue))
{
if(dict.TryUpdate(key, updateFactory(curValue), curValue))
return true;
// if we're looping either the key was removed by another thread,
// or another thread changed the value, so we start again.
}
return false;
}
As said, because it can loop, it's only atomic as observed from the outside if there are no side-effects in the Func
.
(Edit: Deleting a potential short-cut that is really too fraught to generally be used, and likely to bite someone who tried it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With