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();
}
  1. SomePart's explicitly inherited from Lazy<Task<>> so it's clear that it's lazy and asyncronous.

  2. Calling base constructor wraps lazyPartFactory to Task.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 to base(lazyPartFactory)

  3. SlowPart is accessible through TaskAwaiter. So SomePart' public interface is:

    • var eagerValue = somePart.EagerPart;
    • var slowValue = await somePart;