When you have a lazy-created value, it’s often useful to lazy-create it in an asynchronous fashion. A simple Lazy<T> provides lazy initialization, but the initialization executes synchronously when the value is created.
The idea is to have a lazy-initialized task, which represents the initialization of the resource.
The factory delegate passed to the constructor can be either synchronous (Func<T>) or asynchronous (Func<Task<T>>); either way, it will be run on a thread pool thread. It will not be executed more than once, even when multiple threads attempt to start it simultaneously (this is guaranteed by the Lazy type).
There are two “triggers” which can start the initialization: awaiting an AsyncLazy<T> instance or explicitly calling Start. When the factory delegate completes, the value is available, and any methods awaiting the AsyncLazy<T> instance receive the value.
It takes a few minutes to wrap your head around the theory, but it’s really easy in practice:
The AsyncLazy<T> type is now part of Nito.AsyncEx, which you can get via NuGet.