有没有办法将ConcurrentDictionary.TryUpdate与lambda表达式一起使用?

时间:2012-09-02 22:21:12

标签: c# .net concurrency

我有一个简单的场景,我想更新现有项目的值。只有AddOrUpdate方法提供了一个委托,我可以在其中更新旧值。但是,如果密钥不存在,我不想添加任何内容。此外TryUpdate方法没有重载,我可以获得旧值。有没有办法用当前的API做到这一点?

这是我要找的签名:

bool TryUpdate(TKey key, Func<TValue,TValue> updateValueFactory)

1 个答案:

答案 0 :(得分:16)

你必须准备循环并且可能多次调用Func(与使用一个GetOrAdd的重载相同)。这意味着如果Func具有副作用,则它看起来不是来自外部的原子。实际上,Func s不应该有副作用,但它们总是有一些成本,所以不能忽略重复调用的可能性:

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;
}

如上所述,因为它可以循环,如果Func中没有副作用,它只是从外部观察到的原子。

(编辑:删除一个非常普遍使用的潜在捷径,并且可能会咬人尝试过它。)