Say I have a class that needs to perform some async initialization using an InitializeAsync() method. I want to make sure that the initialization is performed only once. If
I have a blog post that covers a few different options for doing "asynchronous constructors".
Normally, I prefer asynchronous factory methods, because I think they're simpler and a bit safer:
public class MyService
{
private MyService() { }
public static async Task<MyService> CreateAsync()
{
var result = new MyService();
result.Value = await ...;
return result;
}
}
AsyncLazy<T> is a perfectly good way of defining a shared asynchronous resource (and may be a better conceptual match for a "service", depending on how it is used). The one advantage of the async factory method approach is that it's not possible to create an uninitialized version of MyService.
I'd go with AsyncLazy<T> (slightly modified version):
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory)) { }
public AsyncLazy(Func<Task<T>> taskFactory) :
base(() => Task.Run(() => taskFactory())) { }
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}
And consume it like this:
private AsyncLazy<bool> asyncLazy = new AsyncLazy<bool>(async () =>
{
await DoStuffOnlyOnceAsync()
return true;
});
Note i'm using bool simply because you have no return type from DoStuffOnlyOnceAsync.
Edit:
Stephan Cleary (of course) also has an implementation of this here.
Yes. Use Stephen Cleary's AsyncLazy (available on the AsyncEx nuget):
private static readonly AsyncLazy<MyResource> myResource = new AsyncLazy<MyResource>(
async () =>
{
var ret = new MyResource();
await ret.InitAsync();
return ret;
}
);
public async Task UseResource()
{
MyResource resource = await myResource;
// ...
}
Or the visual studio SDK's AsyncLazy if you prefer a Microsoft implementation.