C# 在C中尝试从ConcurrentDictionary中删除键值对#

C# 在C中尝试从ConcurrentDictionary中删除键值对#,c#,concurrency,concurrentdictionary,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
上有这样一个方法

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;
    }
}
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;
    }
}
ConcurrentDictionary dict=。。。;
///东西
int keyTryToRemove=1337;
字符串valTryToRemove=“someValue”;
布尔成功=假;
锁(钥匙拆卸){
字符串val;
if(dict.TryRemove(keyTryToRemove,out val)){
if(val==valTryToRemove){
成功=真实;
}
否则{//重新插入值,丑陋!
dict[keyTryToRemove]=val;
成功=错误;
}
}否则{
成功=错误;
}
}

我会这样做

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

您可以在
IDictionary
上编写这样的扩展方法

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;
    }
}
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;
    }
}
公共静态类字典帮助器
{
公共静态bool tryremoviefvalue(此IDictionary所有者、TKey键、TValue值)
{
var成功=false;
锁(所有者)
{
t现有价值;
if(所有者.TryGetValue(键,out existingValue))
{
如果(值等于(现有值))
{
所有者。移除(密钥);
成功=真实;
}
}
}
回归成功;
}
}
由于类实现了(尽管是显式的),因此,您可以简单地将其强制转换为后面的类,并使用如下方法:

bool success = ((ICollection<KeyValuePair<TKey, TValue>>)dict).Remove(
    new KeyValuePair<TKey, TValue>(key, value));
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));
    }
}
因此示例代码变得简单:

bool success = dict.TryRemove(key, value);

下面是一段代码,简化了一些步骤

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;
}
readonly对象_locker=new object();
只读ConcurrentDictionary _dict=新建ConcurrentDictionary();
公共bool TryRemove(整型键,字符串值)
{
var成功=false;
锁(储物柜)
{
if(_dict.ContainsKey(key)&&&&u dict[key]==值)
{
字符串val;
成功=_dict.TryRemove(key,out val);
}
}
回归成功;
}

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

它已经存在:如果a
TryGetValue
返回true且值匹配,则执行a
删除操作怎么样?但是您仍然需要锁。@Igor根据键删除并返回值,如果键和值都匹配,OP希望删除条目。他们甚至在那里使用它。@Igor那正是我不想要的。我想有条件地删除该值,只要它与我传递给它的值匹配。@juharr-啊,我错过了。什么是
lockForDictionary
?是的,这比我在回答中做的要好得多。只能锁上钥匙吗?我想是的,但我想确认这是case@JohnCarpenter不,您希望锁定特定字典实例。我将把它留给您来决定如何实现,但我也不会将字典本身用作锁,而只是一个专门为锁定而创建的
对象。@johncarcenter如何保证密钥是线程安全的?你永远不想使用一个外部实体拥有的对象作为锁哇,这很酷,我想这正是我想要的。有一个问题,这仍然是线程安全的,对吗?@johncarcenter-是的,我刚刚检查过。它使用与public
TryRemove
相同的内部实现-您在有人发布原子解决方案后回答了这个问题,尽管我感谢您在回答问题时付出的努力。不客气!这里的每个答案都略有不同。这些差异在多线程代码中可能会有很大的性能差异。在上面的代码中,检查字典中的值而不删除。这是一个很大的问题,因为添加和删除是一项昂贵的操作。只有当满足移除条件时,该值才会被移除。