C#如何更新BlockingCollection中的元素<;T>;?

C#如何更新BlockingCollection中的元素<;T>;?,c#,concurrency,C#,Concurrency,我有一个ConcurrentDictionaryRapper类,它包装了ConcurrentDictionary,并实现了IProducerConsumerCollection接口,因此我可以将它与BlockingCollection一起使用。生产者将使用一个键向BlockingCollection添加值。其思想是,如果键存在,我们将替换底层字典中的值。我的ConcurrentDictionaryRapper.TryAdd()方法如下: public bool TryAdd(KeyValuePa

我有一个
ConcurrentDictionaryRapper
类,它包装了
ConcurrentDictionary
,并实现了
IProducerConsumerCollection
接口,因此我可以将它与
BlockingCollection
一起使用。生产者将使用一个键向BlockingCollection添加值。其思想是,如果键存在,我们将替换底层字典中的值。我的
ConcurrentDictionaryRapper.TryAdd()
方法如下:

public bool TryAdd(KeyValuePair<TKey, TValue> item)
{
    _wrapped[item.Key] = item.Value
    return true;
}
public bool TryAdd(键值对项目)
{
_包装的[item.Key]=item.Value
返回true;
}
我看到的问题是,如果值被替换,BlockingCollection会将其视为一个加法

var wrapper = new ConcurrentDictionaryWrapper<string, object>();
var bc = new BlockingCollection<KeyValuePair<string, object>>(wrapper);
bc.TryAdd(new KeyValuePair<string, object>("key", new object()));
bc.TryAdd(new KeyValuePair<string, object>("key", new object()));
wrapper.Count; # returns 1
bc.Count; # returns 2
var wrapper=new concurrentdirectionarywrapper();
var bc=新的BlockingCollection(包装器);
TryAdd(newkeyvaluepair(“key”,newobject());
TryAdd(newkeyvaluepair(“key”,newobject());
包装器。计数;#返回1
卑诗省伯爵返回2
我不能在上面的
TryAdd()
中返回false,因为BlockingCollection将引发InvalidOperationException


有没有办法达到我想要的行为?我希望这一点尽可能简单,但似乎没有一种方法可以通过实现
IProducerConsumerCollection
来实现BlockingCollection的这种“添加或更新”行为。我想避免在对BlockingCollection调用
TryAdd()
之前必须
TryTake()
——我可能只需要在字典周围使用一个标准锁,并将生产者/消费者与
AutoResetEvent

同步,也许更合适的方法不是替换,而是将以前的项目标记为无效。为每个值保留一个布尔标志。添加具有现有键的项时,查找上一个项,将其标志设置为false,并添加标志设置为true的新项


然后,当消费者获得该商品时,它将检查该商品是否有效。如果没有,它将扔掉它,并要求新的

这里有相当大的摩擦,BlockingCollection保持自己的计数,而不使用IProducerConsumerCollection.count实现。因此,由于TryAdd()没有失败,BlockingCollection现在确信集合中有两项。即使你只能找回其中一个。因此,您当然不能让它保持原样,您的代码将始终死锁

您需要的是一个BlockingCollection方法,如果项目已经存在,它将返回false或静默失败。但它没有一个,无效操作例外是不可避免的。你可以抓住它,但那太难看了

另一种方法是Contains()方法,如果TryAdd()返回true,您可以使用它来避免调用TryAdd()。但是现在这个集合不再是线程安全的了。这就是为什么BlockingCollection没有这种方法


这是一块石头,一个艰难的地方,你不能让它像想象的那样工作。你必须自己旋转。最好是窃取线程主控程序的代码,中的有界缓冲区应该是正确设计锁的良好开端。

这会起作用,但我想它不会像使用简单的锁进行数据访问和使用事件原语同步线程那样有效?感谢您的回答,这证实了我的怀疑。我被误导了——我认为那里的例子是有效的,因为没有一个项目正在被“更新”,因为它们都在被更新之前被主线程消耗掉了。