简体   繁体   English

C#ConcurrentDictionary条件添加

[英]C# ConcurrentDictionary conditional Add

I am trying to use ConcurrentDictionary to implement a cap limited cache. 我正在尝试使用ConcurrentDictionary来实现上限缓存。 When the cache reaches its capacity, further additions of new items are rejected. 当缓存达到其容量时,将拒绝添加其他新项目。 The code snippet is as follows: 代码片段如下:

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

My question here if the cache is full what should I return here? 我的问题是,如果缓存已满,我应该在这里返回什么? null? 空值? or what? 要不然是啥?

You have two options: 您有两种选择:

  • Write a new concurrrent data struct to manage your cache constraints. 编写新的并发数据结构以管理您的缓存约束。 This is harder but if such a struct is going to be used in several places within your solution thet go for this one. 这比较困难,但是如果要在解决方案中的多个地方使用这样的结构,那就去做吧。
  • Delegate cache's constraints management to the class that actually holds the cache. 将缓存的约束管理委托给实际持有缓存的类。 This is easier. 这比较容易。

@Kirill Polishchuck answer is an example of the second alternative, but I belive it is not threadsafe so I would change it like so it ends up like: @Kirill Polishchuck的答案是第二种选择的一个例子,但是我相信它不是线程安全的,所以我将其更改为如下所示:

if (!this.IsFull())
{
    // your logic here
    this.cache.AddOrUpdate(key, k=> new List<MyObject> { value };);
}
else
{
     // logic
}

For the first alternative here is a sample of what you could do to implement it. 对于第一种选择,这里是您可以执行该操作的示例。 We implement IDictonary<TKey,TValue> interface and we lock on those operations that require so. 我们实现IDictonary<TKey,TValue>接口,并锁定需IDictonary<TKey,TValue>那些操作。 Also, the class does not allow further insertions if _maxCount has been surpassed: 另外,如果已超过_maxCount ,则该类不允许进一步插入:

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

With this other alternative you simply pass a MaxCount parameter to your collection, you can change it to accept a Func<bool> so that the dictionary can figure out whether to add more items or not, this way you can pass your IsFull method to it. 使用此替代方法,您只需将MaxCount参数传递给您的集合,就可以将其更改为接受Func<bool>以便字典可以确定是否添加更多项目,从而可以将IsFull方法传递给它。

Beware: This is demo code, it is just a sample, it is not thread safe to enumarate, adjust it to your needs. 当心:这是演示代码,仅是示例,枚举不是线程安全的,请根据您的需要进行调整。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM