Force C# async tasks to be lazy?
I'm not sure exactly why you want to avoid using Lazy<Task<>>,
, but if it's just for keeping the API easier to use, as this is a property, you could do it with a backing field:
public class SomePart
{
private readonly Lazy<Task<SlowPart>> _lazyPart;
public SomePart(OtherPart eagerPart, Func<Task<SlowPart>> lazyPartFactory)
{
_lazyPart = new Lazy<Task<SlowPart>>(lazyPartFactory);
EagerPart = eagerPart;
}
OtherPart EagerPart { get; }
Task<SlowPart> LazyPart => _lazyPart.Value;
}
That way, the usage is as if it were just a task, but the initialisation is lazy and will only incur the work if needed.
@Max' answer is good but I'd like to add the version which is built on top of Stephen Toub' article mentioned in comments:
public class SomePart: Lazy<Task<SlowPart>>
{
public SomePart(OtherPart eagerPart, Func<Task<SlowPart>> lazyPartFactory)
: base(() => Task.Run(lazyPartFactory))
{
EagerPart = eagerPart;
}
public OtherPart EagerPart { get; }
public TaskAwaiter<SlowPart> GetAwaiter() => Value.GetAwaiter();
}
SomePart's explicitly inherited from
Lazy<Task<>>
so it's clear that it's lazy and asyncronous.Calling base constructor wraps
lazyPartFactory
toTask.Run
to avoid long block if that factory needs some cpu-heavy work before real async part. If it's not your case, just change it tobase(lazyPartFactory)
SlowPart is accessible through TaskAwaiter. So SomePart' public interface is:
var eagerValue = somePart.EagerPart;
var slowValue = await somePart;