Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can constructors be async?

I have a project where I'm trying to populate some data in a constructor:

public class ViewModel {     public ObservableCollection<TData> Data { get; set; }      async public ViewModel()     {         Data = await GetDataTask();     }      public Task<ObservableCollection<TData>> GetDataTask()     {         Task<ObservableCollection<TData>> task;          //Create a task which represents getting the data         return task;     } } 

Unfortunately, I'm getting an error:

The modifier async is not valid for this item

Of course, if I wrap in a standard method and call that from the constructor:

public async void Foo() {     Data = await GetDataTask(); } 

it works fine. Likewise, if I use the old inside-out way

GetData().ContinueWith(t => Data = t.Result); 

That works too. I was just wondering why we can't call await from within a constructor directly. There are probably lots of (even obvious) edge cases and reasons against it, I just can't think of any. I've also search around for an explanation, but can't seem to find any.

like image 976
Marty Neal Avatar asked Nov 16 '11 01:11

Marty Neal


People also ask

Can you async a constructor?

A simple answer for that: No, we can't! Currently, class constructors do not return types, and an asynchronous method should return a Task type.

Can JavaScript constructor be async?

You can only use async/await where you can use promises because they are essentially syntax sugar for promises. You can't use promises in a constructor because a constructor must return the object to be constructed, not a promise.

Can we make constructor async in C#?

There is no simple way to make constructors async in C#, at least while keeping them as constructors. Constructors can't return a value in the . NET runtime. And the use cases for async constructors can be solved with factory methods that are async instead.

Can you 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.


2 Answers

Since it is not possible to make an async constructor, I use a static async method that returns a class instance created by a private constructor. This is not elegant but it works ok.

public class ViewModel        {            public ObservableCollection<TData> Data { get; set; }             //static async method that behave like a constructor            async public static Task<ViewModel> BuildViewModelAsync()       {                ObservableCollection<TData> tmpData = await GetDataTask();           return new ViewModel(tmpData);     }             // private constructor called by the async method     private ViewModel(ObservableCollection<TData> Data)     {         this.Data = Data;        } }   
like image 57
Pierre Poliakoff Avatar answered Oct 01 '22 13:10

Pierre Poliakoff


Constructor acts very similarly to a method returning the constructed type. And async method can't return just any type, it has to be either “fire and forget” void, or Task.

If the constructor of type T actually returned Task<T>, that would be very confusing, I think.

If the async constructor behaved the same way as an async void method, that kind of breaks what constructor is meant to be. After constructor returns, you should get a fully initialized object. Not an object that will be actually properly initialized at some undefined point in the future. That is, if you're lucky and the async initialization doesn't fail.

All this is just a guess. But it seems to me that having the possibility of an async constructor brings more trouble than it's worth.

If you actually want the “fire and forget” semantics of async void methods (which should be avoided, if possible), you can easily encapsulate all the code in an async void method and call that from your constructor, as you mentioned in the question.

like image 29
svick Avatar answered Oct 01 '22 13:10

svick