C#ConcurrentDictionary条件加法
我正在尝试使用ConcurrentDictionary实现一个上限有限的缓存。当缓存达到其容量时,将拒绝进一步添加新项。代码片段如下所示:C#ConcurrentDictionary条件加法,c#,synchronization,concurrentdictionary,C#,Synchronization,Concurrentdictionary,我正在尝试使用ConcurrentDictionary实现一个上限有限的缓存。当缓存达到其容量时,将拒绝进一步添加新项。代码片段如下所示: var result = this.cache.AddOrUpdate( key, (key1) => { if (!this.IsFull()) { return new List<MyObject> { value }; }
var result = this.cache.AddOrUpdate(
key,
(key1) =>
{
if (!this.IsFull())
{
return new List<MyObject> { value };
}
what to return here??
},
(key1, value1) =>
{
value1.Add(value);
return value1;
});
var result=this.cache.AddOrUpdate(
钥匙
(键1)=>
{
如果(!this.IsFull())
{
返回新列表{value};
}
在这里还什么??
},
(键1,值1)=>
{
价值1.增加(价值);
返回值1;
});
我的问题是如果缓存已满,我应该返回什么?无效的还是什么?您有两个选择:
- 编写新的Concurrent数据结构以管理缓存约束。这很难,但如果这样的结构将在解决方案中的多个地方使用,那么就使用这个结构
- 将缓存的约束管理委托给实际保存缓存的类。这比较容易
if (!this.IsFull())
{
// your logic here
this.cache.AddOrUpdate(key, k=> new List<MyObject> { value };);
}
else
{
// logic
}
使用另一种方法,您只需将MaxCount参数传递给集合,就可以将其更改为接受Func
,这样字典就可以确定是否要添加更多项,这样您就可以将IsFull
方法传递给它
注意:这是演示代码,它只是一个示例,枚举不是线程安全的,请根据您的需要进行调整。我想您可能会抛出异常。或者将
IsFull
签出移动到AddOrUpdate
之前。应该注意,根据下面的说明,添加更新代理在锁之外调用,因此您可能希望编写自己的代码来执行此操作,包括锁定。我可以将两个代理包装在锁里面吗(this){…}?最好总是创建一个仅用于锁定的对象,而不要使用类似于lock(this)
的东西。另外,AddOrUpdate
将具有一些锁定,但在其外部调用代理。因此,最好是锁定包含所有代码,而不要使用AddOrUpdate
。实际上,在这一点上,你甚至可以使用一个普通的字典,因为你将自己处理线程安全问题。
public class MaxCountDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> _dictionary;
private readonly object _lock;
public MaxCountDictionary(int maxCount) : this(maxCount, EqualityComparer<TKey>.Default) { }
public MaxCountDictionary(int maxCount, IEqualityComparer<TKey> equalityComparer)
{
_lock = new object();
MaxCount = maxCount;
_dictionary = new Dictionary<TKey, TValue>(equalityComparer);
}
public int MaxCount { get; }
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _dictionary.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(KeyValuePair<TKey, TValue> item) => Add(item.Key, item.Value);
public void Clear()
{
lock (_lock)
{
_dictionary.Clear();
}
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
lock (_lock)
{
return ((IDictionary<TKey, TValue>) _dictionary).Contains(item);
}
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
lock (_lock)
{
((IDictionary<TKey, TValue>) _dictionary).CopyTo(array, arrayIndex);
}
}
public bool Remove(KeyValuePair<TKey, TValue> item) => Remove(item.Key);
public int Count
{
get
{
lock (_lock)
{
return _dictionary.Count;
}
}
}
public bool IsReadOnly => ((IDictionary<TKey, TValue>) _dictionary).IsReadOnly;
public bool ContainsKey(TKey key)
{
lock (_lock)
{
return _dictionary.ContainsKey(key);
}
}
public void Add(TKey key, TValue value)
{
lock (_lock)
{
if (_dictionary.Count < MaxCount) _dictionary.Add(key, value);
}
}
public bool Remove(TKey key)
{
lock (_lock)
{
return _dictionary.Remove(key);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
lock (_lock)
{
return _dictionary.TryGetValue(key, out value);
}
}
public TValue this[TKey key]
{
get
{
lock (_lock)
{
return _dictionary[key];
}
}
set
{
lock (_lock)
{
if (_dictionary.ContainsKey(key) || _dictionary.Count < MaxCount) _dictionary[key] = value;
}
}
}
public ICollection<TKey> Keys
{
get
{
lock (_lock)
{
return _dictionary.Keys.ToArray();
}
}
}
public ICollection<TValue> Values
{
get
{
lock (_lock)
{
return _dictionary.Values.ToArray();
}
}
}
public void AddOrUpdate(TKey key, TValue value, Func<TKey, TValue, TValue> updateValueFactory)
{
lock (_lock)
{
if (_dictionary.ContainsKey(key))
_dictionary[key] = updateValueFactory(key, value);
else if (_dictionary.Count < MaxCount) _dictionary[key] = value;
}
}
}