public enum CacheEventType
{
ADD,
REMOVE
}
public class Cache<K, V>
{
public const int CheckInterval = 1000;
private int _timeoutSeconds;
private SortedList<Timeout, K> timeouts = new SortedList<Timeout, K>();
private Dictionary<K, V> items = new Dictionary<K, V>();
private Timer timer;
private object locker = new object();
public delegate void CacheEventHandler(object source, CacheEvent<K, V> e);
public event CacheEventHandler changed;
public Cache(int timeoutSeconds) : this(timeoutSeconds,CheckInterval){}
public Cache(int timeoutSeconds, int checkInterval)
{
this._timeoutSeconds = timeoutSeconds;
timer = new Timer(PurgeCache, "Cache", checkInterval, checkInterval); //purge cache
}
private void PurgeCache(object data)
{
lock (locker)
{
for (int i = timeouts.Count - 1; i >= 0; i--)
{
if (timeouts.Keys[i].IsExpired())
{
K key = timeouts.Values[i];
timeouts.RemoveAt(i);
V value = items[key];
items.Remove(key);
FireCacheEvent(key, value, CacheEventType.REMOVE);
}
else
{
break; //don't need to loop further
}
}
}
}
public void Put(K key, V value)
{
Put(key, value, _timeoutSeconds);
}
public void Put(K key, V value, int timeoutSeconds)
{
lock (locker)
{
timeouts.Add(new Timeout(timeoutSeconds), key);
items.Add(key, value);
FireCacheEvent(key, value, CacheEventType.ADD);
}
}
public V Get(K key)
{
lock (locker)
{
if (items.ContainsKey(key))
{
return items[key];
}
return default(V);
}
}
public bool Contains(K key)
{
lock (locker)
{
return items.ContainsKey(key);
}
}
private void FireCacheEvent(K key, V value, CacheEventType type)
{
if (changed != null)
{
changed(this, new CacheEvent<K, V>(key, value, type));
}
}
}
public class Timeout : IComparable<Timeout>
{
private readonly DateTime exitTime;
public Timeout(int seconds)
{
exitTime = DateTime.Now.AddSeconds(seconds);
}
public bool IsExpired()
{
if (exitTime < DateTime.Now)
{
return true;
}
return false;
}
public int CompareTo(Timeout timeout)
{
return timeout.exitTime.CompareTo(exitTime);
}
public override string ToString()
{
return exitTime.ToString("yyyyMMdd HH:mm:ss");
}
}
public class CacheEvent<K, V> : EventArgs
{
private K _key;
private V _value;
private readonly CacheEventType _type;
public CacheEvent(K key, V value, CacheEventType type)
{
_key = key;
_value = value;
_type = type;
}
public K Key
{
get { return _key; }
}
public V Value
{
get { return _value; }
}
public CacheEventType Type
{
get { return _type; }
}
}
//Sample Form with TextBox & ListBox that allows you to add items to cache
//and shows you the current content of cache
public partial class Form1 : Form
{
private Cache<string, string> cache = new Cache<string, string>(5);
DataTable itemsDT = new DataTable();
public Form1()
{
InitializeComponent();
itemsDT.Columns.Add("Item");
this.itemListBox.DataSource = itemsDT;
this.itemListBox.DisplayMember = "Item";
this.itemListBox.ValueMember = "Item";
cache.changed += new Cache<string, string>.CacheEventHandler(cache_changed);
}
void cache_changed(object source, CacheEvent<string, string> e)
{
if (this.InvokeRequired)
{
this.Invoke(new Cache<string, string>.CacheEventHandler(cache_changed), new object[] { source, e }
);
}
else
{
if(e.Type==CacheEventType.ADD)
{
DataRow row = itemsDT.NewRow();
row["Item"] = e.Value;
itemsDT.Rows.Add(row);
}
else if (e.Type == CacheEventType.REMOVE)
{
DataRow[] row = itemsDT.Select(String.Format("Item='{0}'", e.Value));
itemsDT.Rows.Remove(row[0]);
}
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if(e.KeyChar==(char)Keys.Enter)
{
if (!cache.Exists(itemTextBox.Text))
{
cache.Put(itemTextBox.Text, itemTextBox.Text);
}
itemTextBox.Clear();
}
}
}
Comments
Post a Comment