using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public static async Task Main()
var task1 = Task.Run(async () => await test.AsyncString());
var task2 = Task.Run(async () => await test.AsyncString());
var task3 = Task.Run(async () => await test.AsyncString());
var results = await Task.WhenAll(task1, task2, task3);
Console.WriteLine(string.Join(", ", results));
_lazyString = new AsyncLazy<string>(longRunningOperation);
public async Task<string> AsyncString()
Console.WriteLine($"{_sw.Elapsed}: Started awaiting lazy string.");
var result = await _lazyString;
Console.WriteLine($"{_sw.Elapsed}: Finished awaiting lazy string.");
async Task<string> longRunningOperation()
Console.WriteLine($"{_sw.Elapsed}: longRunningOperation() started.");
Console.WriteLine($"{_sw.Elapsed}: longRunningOperation() finished.");
readonly Stopwatch _sw = Stopwatch.StartNew();
readonly AsyncLazy<string> _lazyString;
public class AsyncLazy<T> : Lazy<Task<T>>
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Factory.StartNew(valueFactory))
public AsyncLazy(Func<Task<T>> taskFactory) :
base(() => Task.Factory.StartNew(taskFactory).Unwrap())
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }