C # ConcurrentDictionary условно Добавить - PullRequest
0 голосов
/ 15 октября 2018

Я пытаюсь использовать 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;
    });

Мой вопрос здесь, если кэш заполнен, что я должен вернуть сюда?ноль?или что?

1 Ответ

0 голосов
/ 15 октября 2018

У вас есть два варианта:

  • Создать новую параллельную структуру данных для управления вашими ограничениями кэша.Это сложнее, но если такая структура будет использоваться в нескольких местах вашего решения, то пойдем на это.
  • Делегирование управления ограничениями кэша классу, который фактически содержит кэш.Это проще.

@ Кирилл Полищук ответ - пример второй альтернативы, но я верю, что это не потокобезопасно, поэтому я бы изменил его так, чтобы оно получилось так:

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

Для первого варианта здесь приведен пример того, что вы могли бы сделать для его реализации.Мы реализуем интерфейс IDictonary<TKey,TValue> и блокируем те операции, которые этого требуют.Кроме того, класс не разрешает дальнейшие вставки, если _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;
        }
    }
}

С помощью этой другой альтернативы вы просто передаете параметр MaxCount в свою коллекцию, вы можете изменить его, чтобы принять Func<bool>чтобы словарь мог определить, добавлять ли элементы больше или нет, таким образом, вы можете передать ему свой метод IsFull.

Осторожно: Это демонстрационный код, это всего лишь пример, его нельзя перечислить потоком, настройте его под свои нужды.

...