Enforce an async method to be called once

前端 未结 3 1267
广开言路
广开言路 2020-12-29 09:53

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

相关标签:
3条回答
  • 2020-12-29 10:01

    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.

    0 讨论(0)
  • 2020-12-29 10:05

    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.

    0 讨论(0)
  • 2020-12-29 10:14

    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.

    0 讨论(0)
提交回复
热议问题