I want to implement an expiration time on a Lazy object. The expiration cooldown must start with the first retrieve of the value. If we get the value, and the expiration time is
I needed the same thing. But I would prefer an implementation without locked reads when there is no write.
public class ExpiringLazy
{
private readonly Func factory;
private readonly TimeSpan lifetime;
private readonly ReaderWriterLockSlim locking = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
private T value;
private DateTime expiresOn = DateTime.MinValue;
public ExpiringLazy(Func factory, TimeSpan lifetime)
{
this.factory = factory;
this.lifetime = lifetime;
}
public T Value
{
get
{
DateTime now = DateTime.UtcNow;
locking.EnterUpgradeableReadLock();
try
{
if (expiresOn < now)
{
locking.EnterWriteLock();
try
{
if (expiresOn < now)
{
value = factory();
expiresOn = DateTime.UtcNow.Add(lifetime);
}
}
finally
{
locking.ExitWriteLock();
}
}
return value;
}
finally
{
locking.ExitUpgradeableReadLock();
}
}
}
}