Before I wrote this I searched and found a number of solutions that make use of a caching provider to handle a set of items. I felt that was too cumbersome of an approach and set out to create a class that could cache a single value, similar to the way Lazy<T>
manages the initialization of a single value.
I'm having trouble determining the thread-safety of this implementation, specifically where lock
statements should be used. Can any experts on working with multi-threaded applications spot where I may have gone wrong? Or is this approach sound?
public class Cached<T> {
private readonly TimeSpan _duration;
private DateTime _expiration;
private Lazy<T> _value;
private readonly Func<T> _valueFactory;
public T Value {
get {
// Do I need locking while checking the expiration?
if (DateTime.Now >= _expiration)
RefreshValue();
return _value.Value;
}
}
public Cached(Func<T> valueFactory, TimeSpan duration) {
_duration = duration;
_valueFactory = valueFactory;
RefreshValue();
}
private void RefreshValue() {
// Is this sufficient while updating the expiration and value?
lock (this) {
_value = new Lazy<T>(() => _valueFactory());
_expiration = DateTime.Now.Add(_duration);
}
}
}
I'm using Lazy<T>
for the value getter because it's possible that the cached value will be (1) expensive to load and (2) not immediately needed.