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

我正在尝试使用ConcurrentDictionary实现一个上限有限的缓存。当缓存达到其容量时,将拒绝进一步添加新项。代码片段如下所示:

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数据结构以管理缓存约束。这很难,但如果这样的结构将在解决方案中的多个地方使用,那么就使用这个结构
  • 将缓存的约束管理委托给实际保存缓存的类。这比较容易
@Kirill Polishchuck的答案是第二种选择的一个例子,但我相信它不是线程安全的,所以我会像这样修改它,使其最终像:

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