Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize an object using async-await pattern

Tags:

I'm trying to follow RAII pattern in my service classes, meaning that when an object is constructed, it is fully initialized. However, I'm facing difficulties with asynchronous APIs. The structure of class in question looks like following

class ServiceProvider : IServiceProvider // Is only used through this interface {     public int ImportantValue { get; set; }     public event EventHandler ImportantValueUpdated;      public ServiceProvider(IDependency1 dep1, IDependency2 dep2)     {         // IDependency1 provide an input value to calculate ImportantValue         // IDependency2 provide an async algorithm to calculate ImportantValue     } } 

I'm also targeting to get rid of side-effects in ImportantValue getter, to make it thread-safe.

Now users of ServiceProvider will create an instance of it, subscribe to an event of ImportantValue change, and get the initial ImportantValue. And here comes the problem, with the initial value. Since the ImportantValue is calculated asynchronously, the class cannot be fully initialized in constructor. It may be okay to have this value as null initially, but then I need to have some place where it will be calculated first time. A natural place for that could be the ImportantValue's getter, but I'm targeting to make it thread-safe and with no side-effects.

So I'm basically stuck with these contradictions. Could you please help me and offer some alternative? Having value initialized in constructor while nice is not really necessary, but no side-effects and thread-safety of property is mandatory.

Thanks in advance.

EDIT: One more thing to add. I'm using Ninject for instantiation, and as far as I understand, it doesn't support async methods to create a binding. While approach with initiating some Task-based operation in constructor will work, I cannot await its result.

I.e. two next approaches (offered as answers so far) will not compile, since Task is returned, not my object:

Kernel.Bind<IServiceProvider>().ToMethod(async ctx => await ServiceProvider.CreateAsync()) 

or

Kernel.Bind<IServiceProvider>().ToMethod(async ctx =>  {     var sp = new ServiceProvider();     await sp.InitializeAsync(); }) 

Simple binding will work, but I'm not awaiting the result of asynchronous initialization started in constructor, as proposed by Stephen Cleary:

Kernel.Bind<IServiceProvider>().To<ServiceProvider>(); 

... and that's not looking good for me.

like image 820
Haspemulator Avatar asked Apr 09 '13 16:04

Haspemulator


People also ask

Can I use await in constructor?

Since performing an asynchronous call to its completion in the constructor is not an option, we can still start a call in the constructor. We'd start it in the constructor, save the unsettled Promise in an instance variable, and then await for its completion in the methods that need it.

What is the async await pattern?

In computer programming, the async/await pattern is a syntactic feature of many programming languages that allows an asynchronous, non-blocking function to be structured in a way similar to an ordinary synchronous function.

Does async await create a new thread?

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.

Can we use await in constructor C#?

It's possible to call this in the constructor, but you can't await an expression that referenced it.


1 Answers

I have a blog post that describes several approaches to async construction.

I recommend the asynchronous factory method as described by Reed, but sometimes that's not possible (e.g., dependency injection). In these cases, you can use an asynchronous initialization pattern like this:

public sealed class MyType {     public MyType()     {         Initialization = InitializeAsync();     }      public Task Initialization { get; private set; }      private async Task InitializeAsync()     {         // Asynchronously initialize this instance.         await Task.Delay(100);     } } 

You can then construct the type normally, but keep in mind that construction only starts the asynchronous initialization. When you need the type to be initialized, your code can do:

await myTypeInstance.Initialization; 

Note that if Initialization is already complete, execution (synchronously) continues past the await.


If you do want an actual asynchronous property, I have a blog post for that, too. Your situation sounds like it may benefit from AsyncLazy<T>:

public sealed class MyClass {     public MyClass()     {         MyProperty = new AsyncLazy<int>(async () =>         {             await Task.Delay(100);             return 13;         });     }      public AsyncLazy<int> MyProperty { get; private set; } } 
like image 86
Stephen Cleary Avatar answered Sep 19 '22 15:09

Stephen Cleary