TryRemove来自C#中ConcurrentDictionary的键值对

时间:2016-09-15 16:55:12

标签: c# concurrency concurrentdictionary

我的场景是我想在ConcurrentDictionary这样的方法。

bool TryRemove(TKey key, TValue value) {
    // remove the value IF the value passed in == dictionary[key]
    // return false if the key is not in the dictionary, or the value is not equal
}

有没有办法同时执行此操作?我很难找到这个场景的答案,尽管这似乎是一个常见的用例。

我可以做这样的事情,但如果我已经使用ConcurrentDictionary,我想避免锁定。我还必须在其他地方GetOrAdd()AddOrUpdate()来电。似乎应该有一个更好的方法ConcurrentDictionary

ConcurrentDictionary<int, string> dict = ...;

/// stuff

int keyTryToRemove = 1337;
string valTryToRemove = "someValue";

bool success = false;
lock(keyTryToRemove) {
    string val;
    if (dict.TryRemove(keyTryToRemove, out val)) {
        if (val == valTryToRemove) {
            success = true;
        }
        else { // reinsert value, UGLY!
            dict[keyTryToRemove] = val;
            success = false;
        }
    } else {
        success = false;
    }
}

4 个答案:

答案 0 :(得分:5)

由于ConcurrentDictionary<TKey, TValue>类实现了(虽然明确地)IDictionary<TKey, TValue>,因此ICollection<KeyValuePair<TKey, TValue>>,您可以简单地将其强制转换为后者并使用Remove方法,如下所示:

bool success = ((ICollection<KeyValuePair<TKey, TValue>>)dict).Remove(
    new KeyValuePair<TKey, TValue>(key, value));

implementation内部使用相同的线程安全方法(另外传递要检查的值)作为公共TryRemove方法 - 完全应该如此。

修改:一般而言,相关方法可用于实施IDictionary<TKey, TValue>(或更准确地说ICollection<KeyValuePair<TKey, TValue>>)的任何类型,例如Dictionary,{ {1}}等通过引入这样的自定义扩展方法:

ConcurrentDictionary

所以示例代码变得简单:

public static class Extensions
{
    public static bool TryRemove<TKey, TValue>(this ICollection<KeyValuePair<TKey, TValue>> source, TKey key, TValue value)
    {
        return source.Remove(new KeyValuePair<TKey, TValue>(key, value));
    }
}

答案 1 :(得分:0)

我做这样的事情

bool success = false;
lock(lockForDictionary) 
{
    string val;
    if (dict.TryGetValue(keyTryToRemove, out val) && val == valTryToRemove) 
    {
        dict.Remove(keyTryToRemove);
        success = true;
    } 
}

答案 2 :(得分:0)

你可以在IDictionary上编写类似这样的扩展方法。

public static class DictionaryHelper
{
    public static bool TryRemoveIfValue<TKey, TValue>(this IDictionary<TKey,TValue> owner, TKey key, TValue value)
    {
        var success = false;
        lock (owner)
        {
            TValue existingValue;
            if (owner.TryGetValue(key, out existingValue))
            {
                if (value.Equals(existingValue))
                {
                    owner.Remove(key);
                    success = true;
                }
            }
        }
        return success;
    }
}

答案 3 :(得分:0)

下面是一段简化步骤的代码。

readonly object _locker = new object();
readonly ConcurrentDictionary<int, string> _dict = new ConcurrentDictionary<int, string>();

public bool TryRemove(int key, string value)
{
    var success = false;
    lock (_locker)
    {
        if (_dict.ContainsKey(key) && _dict[key] == value)
        {
            string val;
            success = _dict.TryRemove(key, out val);
        }
    }
    return success;
}

话虽如此,似乎目标本质上是非原子性的,这就是我们需要锁定的原因。重要的是要问,你的目标是什么,能否以原子方式表达目标。 ConcurrentDictionary的2个有用方法包括TryUpdate和AddOrUpdate。这些方法中的任何一种都有帮助吗?