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).