пятница, 24 сентября 2010 г.

C#: Cash data by time

Часто возникает ситуация когда надо хранить кэш данных, к которым наиболее часто обращаются. Стандартной реализации такой штуки в .NET я не нашел, вот и решил сам поупражняться.
    public class TimeCashDictionary<TKey, TValue> : IDictionary<TKey,TValue>
    {
        protected class TimedValue
        {
            public TimedValue(TValue value)
            {
                LastAccess = DateTime.UtcNow;
                Value = value;
            }
            public TValue Value {get;set;}
            public DateTime LastAccess { get; set; }
        }

        Dictionary<TKey, TimedValue> m_Dict;
        int m_CashSize;
        public int CashSize { get { return m_CashSize; } }

        public TimeCashDictionary(int cashSize)
        {
            m_CashSize = cashSize;
            m_Dict = new Dictionary<TKey, TimedValue>(cashSize+1);
        }

        private void RemoveOldWhenNeed()
        {
            if (m_Dict.Count >= m_CashSize)
            {
                m_Dict.Remove(m_Dict.OrderBy(kv => kv.Value.LastAccess).First().Key);
            }
        }
           
        public void Add(TKey key, TValue value)
        {
            RemoveOldWhenNeed();
            m_Dict.Add(key, new TimedValue(value));
        }

        public bool ContainsKey(TKey key)
        {
            return m_Dict.ContainsKey(key);
        }

        public ICollection<TKey> Keys
        {
            get { return m_Dict.Keys; }
        }

        public bool Remove(TKey key)
        {
            return m_Dict.Remove(key);
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            TimedValue val;
            var res = m_Dict.TryGetValue(key,out val);
            value = res?val.Value:default(TValue);
            if (res)
                val.LastAccess = DateTime.UtcNow;

            return res;
        }

        public ICollection<TValue> Values
        {
            get
            {
                return  new List<TValue>(m_Dict.Values.Select(el => el.Value));
            }
        }

        public TValue this[TKey key]
        {
            get
            {
                var val = m_Dict[key];
                val.LastAccess = DateTime.UtcNow;
                return val.Value;
            }
            set
            {
                RemoveOldWhenNeed();
                m_Dict[key] = new TimedValue(value);
            }
        }

        public void Add(KeyValuePair<TKey, TValue> item)
        {
            RemoveOldWhenNeed();
            (m_Dict as ICollection<KeyValuePair<TKey, TimedValue>>).Add(new KeyValuePair<TKey, TimedValue>(item.Key, new TimedValue(item.Value)));
        }

        public void Clear()
        {
            m_Dict.Clear();
        }

        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return (m_Dict as ICollection<KeyValuePair<TKey, TimedValue>>).Contains(new KeyValuePair<TKey, TimedValue>(item.Key, new TimedValue(item.Value)));
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { return m_Dict.Count; }
        }

        public bool IsReadOnly
        {
            get { return (m_Dict as ICollection<KeyValuePair<TKey, TimedValue>>).IsReadOnly; }
        }

        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return (m_Dict as ICollection<KeyValuePair<TKey, TimedValue>>).Remove(new KeyValuePair<TKey,TimedValue>(item.Key,new TimedValue(item.Value)));
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return m_Dict.Select(kv => new KeyValuePair<TKey, TValue>(kv.Key, kv.Value.Value)).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {

            return m_Dict.GetEnumerator();
        }
    }
 
Используется так:
var tc = new TimeCashDictionary<string, string>(3);

tc["sasha"] = "1";
tc["dima"] = "2";
tc["mike"] = "3";
var  v = tc["sasha"];
tc["katy"] = "4";
tc["max"] = "5";
 

Результатом будет:
sasha,katy,max

Версия сырая и на крутизну использования C# не претендующая, но если вдруг приглянется можете использовать под CC лицензией. :)

Комментариев нет: