I decided to write a simple dictionary to use as a cache:
public class CacheDictionary : Dictionary<string, object>, ICacheDictionary
{
private readonly Dictionary<string, CancellationTokenSource> _expireTasks = new Dictionary<string, CancellationTokenSource>();
private int _defaultExpiration;
public CacheDictionary()
{
_defaultExpiration = 30;
}
public CacheDictionary(int defaultExpiration)
{
_defaultExpiration = defaultExpiration;
}
public T GetOrDefault<T>(string key, Func<T> createDefault)
{
return GetOrDefault(key, createDefault, TimeSpan.FromSeconds(_defaultExpiration));
}
public T Set<T>(string key, Func<T> create)
{
return Set(key, create, TimeSpan.FromSeconds(_defaultExpiration));
}
public T GetOrDefault<T>(string key, Func<T> createDefault, TimeSpan expireIn)
{
return (T)(ContainsKey(key) ? this[key] : Set(key, createDefault, expireIn));
}
public T Set<T>(string key, Func<T> create, TimeSpan expireIn)
{
if (_expireTasks.ContainsKey(key))
{
_expireTasks[key].Cancel();
_expireTasks.Remove(key);
}
var expirationTokenSource = new CancellationTokenSource();
var expirationToken = expirationTokenSource.Token;
Task.Delay(expireIn, expirationToken).ContinueWith(_ => Expire(key), expirationToken);
_expireTasks[key] = expirationTokenSource;
return (T)(this[key] = create());
}
private void Expire(string key)
{
if (_expireTasks.ContainsKey(key))
_expireTasks.Remove(key);
Remove(key);
}
}
The functionality is simple: I can add items into the dictionary and set a timer to expire them. I am wondering if I did everything right. Should I also implement IDisposable
and remove expiration tasks on Dispose? And if I want it to be thread-safe, should I use ConcurrentBag
?