Does this get anywhere near your requirements?
The behaviour falls somewhere between ExecutionAndPublication
and PublicationOnly
.
While the initializer is in-flight all calls to Value
will be handed the same task (which is cached temporarily but could subsequently succeed or fail); if the initializer succeeds then that completed task is cached permanently; if the initializer fails then the next call to Value
will create a completely new initialization task and the process begins again!
public sealed class TooLazy<T>
{
private readonly object _lock = new object();
private readonly Func<Task<T>> _factory;
private Task<T> _cached;
public TooLazy(Func<Task<T>> factory)
{
if (factory == null) throw new ArgumentNullException("factory");
_factory = factory;
}
public Task<T> Value
{
get
{
lock (_lock)
{
if ((_cached == null) ||
(_cached.IsCompleted && (_cached.Status != TaskStatus.RanToCompletion)))
{
_cached = Task.Run(_factory);
}
return _cached;
}
}
}
}