Enforce an async method to be called once
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.
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
.