I implemented a resettable version of .NET Lazy (context: mostly to use it in a MemoryCache for auto refresh purposes on item expiration)
This is a very naive implementation and I am pretty sure there are couple of things that are not okay. In particular, I am not really sure whether the reset is fine. I think the assignment is atomic but I am not sure what can happen when there is an attempt to get the Value while it is resetting at the same (e.g. I am not sure whether the fact that the assignment is atomic is enough to guarantee proper operations).
public class ResettableLazy<T>
{
private Lazy<T> _lazy;
public bool IsValueCreated => _lazy.IsValueCreated;
public T Value => _lazy.Value;
public LazyThreadSafetyMode LazyThreadSafetyMode { get; }
private readonly Func<T> _valueFactory;
public ResettableLazy(Func<T> valueFactory, LazyThreadSafetyMode lazyThreadSafetyMode = LazyThreadSafetyMode.ExecutionAndPublication)
{
_valueFactory = valueFactory;
LazyThreadSafetyMode = lazyThreadSafetyMode;
_lazy = new Lazy<T>(_valueFactory, LazyThreadSafetyMode);
}
public ResettableLazy(Func<T> valueFactory, bool isThreadSafe)
: this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
{
}
public void Reset()
{
_lazy = new Lazy<T>(_valueFactory, LazyThreadSafetyMode);
}
}
And played a bit around with:
public static class Program
{
public static void Main(params string[] args)
{
var lazy = new ResettableLazy<int>(() =>
{
Thread.Sleep(2000);
return new Random().Next();
});
for (var i = 0; i < 1000; i++)
{
if (i % 2 == 0)
{
Thread.Sleep(200);
}
Task.Run(() => Console.WriteLine(lazy.Value));
if (i % 3 == 0)
{
Task.Run(() => lazy.Reset());
}
}
Console.ReadKey();
}
}
Is there any red flags in my implementation?
Lazy<T>
. When it expires you create a new one. IOW, the exact opposite of what you're doing. Instead of resettingLazy
so that it reads from the cache, cache theLazy
so that it expires. \$\endgroup\$ExpirableLazy<T>
taking aResettableLazy<T>
as a parameter. \$\endgroup\$IExpirer<TLazy> where TLazy : ResettableLazy<ExpirableLazy<T>>
\$\endgroup\$