Can constructors be async?
Asked Answered
M

17

472

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.

Monadism answered 16/11, 2011 at 1:19 Comment(4)
No, but in his blog, Stephen Cleary offers a factory method approach as well as others to consider.Creativity
The pattern proposed in this answer works pretty well, it's an offshoot of the factory pattern, but I'm going to start referring to it, specifically, as the async constructor pattern.Poyssick
Please bump this language request: github.com/dotnet/csharplang/discussions/419 - the amount of boilerplate code everyone needs to write to have a fully initialized async object is crazy and completely opposite of the trend in C# (less boilerplate).Wariness
" if I wrap in a standard method and call that from the constructor .. it works fine." Actually, it doesn't. You'll see a warning on the call, due to missing await. DO NOT IGNORE such a warning; it can lead to deadlock; your UI can freeze forever.Craig
P
281

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.

Patrolman answered 16/11, 2011 at 1:49 Comment(4)
I think this hits it closest. await can so often replace .ContinueWith that it was easy for me to forget that it's not so simple. I'm not even sure what I was thinking anymore, but I think I was thinking that await ought to "return" a constructed T (which you point out isn't what an async method can return) because that's was constructors "return" but then when await continues, the contructor doesn't return anything because its a constructor, like void. I'm not even making sense anymore, but your answer was the most helpful. Thanks.Monadism
"If the constructor of type T actually returned Task<T>, that would be very confusing, I think." I disagree. Like async Dispose, it would be very natural.Salute
"async void" Do not do that. The construction of the object is not complete. It can raise the exception which would not be handled and etc.Alicyclic
"it has to be either “fire and forget” void, or Task." -- Stephen Cleary calls the async void methods fire and crash. Which is fair, because exceptions in async void methods are crashing the process by default.Ptosis
F
510

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;   
    }
}  
Forsberg answered 20/9, 2012 at 20:39 Comment(12)
This answer should have much more votes in my opinion. It gives an answer that encapsulates and hides away the need to call an Initialize() method after an item is constructed, thus preventing the potential bug of constructing an object and forgetting to cal its initialize method.Personage
Ag, this would be a great solution if you had control over the constructor but if your class implements an abstract base class, e.g. public class LoginModelValidator : AbstractValidator<Domain.Models.LoginModel> you have a problemNetwork
This approach uses a factory pattern. See another well-written similar answer here.Creativity
You don't always have control over callers, so a factory isn't always the general solution (to restate what Damian said in a more general way)Altamirano
very nice solution @Pierre Poliakoff, love itDynamiter
This is a nice solution from the "user" perspective, but it's quite common in i.e. web applications and you need a lot of boilerplate. It would be great if they would syntactic sugar this behavior in something similar like an async constructor.Wariness
PRoblem is in WinForms, when things are created in the InitializeComponent() method for designer support. In that case I dont think this is a relevant solution.Henze
How would this work with dependency injection? i.e. if BuildViewModelAsync needed some injected classes to do some work before calling the private constructor.Loeb
It's no less elegant than every Python class, because a static method returning an instance is basically the closest thing Python has to a constructor. I think Perl works the same way, as well as Objective-C if my memory serves. I personally don't think that style loses you anything.Spun
@Loeb For dependency injection, you could put the injected object into the constructor of the class calling the static method and then pass it as a parameter into the static method. Granted, that does create a minor coupling. If you want to avoid that completely, you can go one step further and create a static initializer that takes a parameter of your DI container itself and pass that in at startup or similar so that anything calling this static method is completely unaware of construction requirements.Jariah
@Jariah - and then the private method would be async? I think I tried this but was still running into uninitialized errors... need to check thoughLoeb
@Loeb - No private method would need to be async. All async processing gets handled in the Build/Create method, which is public. (Sure, you can create helper private methods for that, which could be made async as needed, but there's no private method that would require async.)Jariah
P
281

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.

Patrolman answered 16/11, 2011 at 1:49 Comment(4)
I think this hits it closest. await can so often replace .ContinueWith that it was easy for me to forget that it's not so simple. I'm not even sure what I was thinking anymore, but I think I was thinking that await ought to "return" a constructed T (which you point out isn't what an async method can return) because that's was constructors "return" but then when await continues, the contructor doesn't return anything because its a constructor, like void. I'm not even making sense anymore, but your answer was the most helpful. Thanks.Monadism
"If the constructor of type T actually returned Task<T>, that would be very confusing, I think." I disagree. Like async Dispose, it would be very natural.Salute
"async void" Do not do that. The construction of the object is not complete. It can raise the exception which would not be handled and etc.Alicyclic
"it has to be either “fire and forget” void, or Task." -- Stephen Cleary calls the async void methods fire and crash. Which is fair, because exceptions in async void methods are crashing the process by default.Ptosis
U
86

Your problem is comparable to the creation of a file object and opening the file. In fact there are a lot of classes where you have to perform two steps before you can actually use the object: create + Initialize (often called something similar to Open).

The advantage of this is that the constructor can be lightweight. If desired, you can change some properties before actually initializing the object. When all properties are set, the Initialize/Open function is called to prepare the object to be used. This Initialize function can be async.

The disadvantage is that you have to trust the user of your class that he will call Initialize() before he uses any other function of your class. In fact if you want to make your class full proof (fool proof?) you have to check in every function that the Initialize() has been called.

The pattern to make this easier is to declare the constructor private and make a public static function that will construct the object and call Initialize() before returning the constructed object. This way you'll know that everyone who has access to the object has used the Initialize function.

The example shows a class that mimics your desired async constructor

public MyClass
{
    public static async Task<MyClass> CreateAsync(...)
    {
        MyClass x = new MyClass();
        await x.InitializeAsync(...)
        return x;
    }

    // make sure no one but the Create function can call the constructor:
    private MyClass(){}

    private async Task InitializeAsync(...)
    {
        // do the async things you wanted to do in your async constructor
    }

    public async Task<int> OtherFunctionAsync(int a, int b)
    {
        return await ... // return something useful
    }

Usage will be as follows:

public async Task<int> SomethingAsync()
{
    // Create and initialize a MyClass object
    MyClass myObject = await MyClass.CreateAsync(...);

    // use the created object:
    return await myObject.OtherFunctionAsync(4, 7);
}
Ute answered 17/7, 2015 at 8:56 Comment(8)
... But the return of an async method must be a Task? How do you get around that?Complaisance
the ideas is not to use a constructor, but a static function that constructs the object ans async Initializes it. So don't do the initialization in the constructor, but in a separate private Initialize function, this Initialize function can return an awaitable Task and thus the static Create function can return an awaitable TaskUte
I'm referring to this as the async constructor pattern from now on. -- IMO, this should be the accepted answer, because it's nice, simple, and too the point -- Nice work!Poyssick
This was very helpful, thanks for sharing! and in enough detail to make it simple to understand. kudosAudacious
Tried it with code-behind of XAML View file (Xamarin.Forms) and I suppose this way of solving the problem is not applicable for my context. Thanks for the idea anyway @HaraldCoppoolse . Error makes total sense: Type 'MyClassViewModel' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter.Disrepair
So why not define the class public then? The only thing you should not do, is to declare the constructor public. Since you won't call this constructor, you don't need a public constructor. If you can't call CreateAsync from XAML, why not use code-behind?Ute
Having a private constructor inhibits the use of that class through dependency injection, making the injection process more complex, isn't it?Wellfavored
If using it in code behind, could you move the functionality to OnAppearing? protected override async void OnAppearing() { base.OnAppearing(); await MethodToUpdateData(); }Arsine
I
4

if you make constructor asynchronous, after creating an object, you may fall into problems like null values instead of instance objects. For instance;

MyClass instance = new MyClass();
instance.Foo(); // null exception here

That's why they don't allow this i guess.

Impertinent answered 16/11, 2011 at 1:28 Comment(4)
You would think so, but that actually doesn't make sense even. If you make a call like 'var o = sqlcmd.BeginExecuteReader();' it's going to assign an IAsyncResult object to o before it continues to the next line. In your example, it can't assign anything to instance until the constructor is completed so it just doesn't make sense to allow the constructor to be asynchronous.Gib
The way I was expecting (hoping actually, "expect" is too strong a word) it to behave was to return the constructed object, but the object would finish constructing when what it was awaiting was ready. Since I think of await as being more of a set-up-a-continuation-and-then-return, I was hoping this might be possible. I wouldn't expect null to be returned.Monadism
Allowing half constructed objects (as is implicit by an async constructor) would break other language constructs, such as the guarantees made by the readonly keyword.Illene
If the constructor of a class C was truly Async you would get a Task<C> that you would have to await.Hedva
U
4

In this particular case, a viewModel is required to launch the task and notify the view upon its completion. An "async property", not an "async constructor", is in order.

I just released AsyncMVVM, which solves exactly this problem (among others). Should you use it, your ViewModel would become:

public class ViewModel : AsyncBindableBase
{
    public ObservableCollection<TData> Data
    {
        get { return Property.Get(GetDataAsync); }
    }

    private Task<ObservableCollection<TData>> GetDataAsync()
    {
        //Get the data asynchronously
    }
}

Strangely enough, Silverlight is supported. :)

Upstroke answered 31/12, 2014 at 18:53 Comment(0)
C
3

I was just wondering why we can't call await from within a constructor directly.

I believe the short answer is simply: Because the .Net team has not programmed this feature.

I believe with the right syntax this could be implemented and shouldn't be too confusing or error prone. I think Stephen Cleary's blog post and several other answers here have implicitly pointed out that there is no fundamental reason against it, and more than that - solved that lack with workarounds. The existence of these relatively simple workarounds is probably one of the reasons why this feature has not (yet) been implemented.

Colly answered 3/5, 2017 at 19:55 Comment(1)
Async constructors are currently being discussed and considered.Euchre
S
1

calling async in constructor maybe cause deadlock, please refer to http://social.msdn.microsoft.com/Forums/en/winappswithcsharp/thread/0d24419e-36ad-4157-abb5-3d9e6c5dacf1

http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115163.aspx

Sitton answered 7/11, 2012 at 21:54 Comment(2)
That's about calling an async method from a constructor (which is possible, but probably not a good idea). This question is about the constructor itself being async (which won't compile at all).Rosati
Many answers are saying "there's no reason it shouldn't be possible", this is a good reason -- also, if libraries start doing async stuff in their constructors (i.e. even .Wait() or .GetResult()) it can cause other issues; for example ASP.NET web forms requires special configuration for async calls to work (i.e. it's not a deadlock, but the execution context just drops off somewhere and never comes back -- even after configuration, it only works within certain parts of the page life cycle...) -- in general, I think hiding async calls in synchronous methods should be considered an anti-pattern.Poyssick
S
1

Some of the answers involve creating a new public method. Without doing this, use the Lazy<T> class:

public class ViewModel
{
    private Lazy<ObservableCollection<TData>> Data;

    async public ViewModel()
    {
        Data = new Lazy<ObservableCollection<TData>>(GetDataTask);
    }

    public ObservableCollection<TData> GetDataTask()
    {
        Task<ObservableCollection<TData>> task;

        //Create a task which represents getting the data
        return task.GetAwaiter().GetResult();
    }
}

To use Data, use Data.Value.

Shankle answered 27/2, 2019 at 2:37 Comment(0)
C
0

you can use Action inside Constructor

 public class ViewModel
    {
        public ObservableCollection<TData> Data { get; set; }
       public ViewModel()
        {              
            new Action(async () =>
            {
                  Data = await GetDataTask();
            }).Invoke();
        }

        public Task<ObservableCollection<TData>> GetDataTask()
        {
            Task<ObservableCollection<TData>> task;
            //Create a task which represents getting the data
            return task;
        }
    }
Clodhopper answered 20/3, 2013 at 8:55 Comment(3)
This creates and uses an async void method, which is not a good idea.Euchre
so you have to use Data = GetDataTask().Result;Clodhopper
No. Result could cause deadlocks. I have a variety of solutions described on my blog.Euchre
P
0

C# doesn't allow async constructors. Constructors are meant to return fast after some brief initialization. You don't expect and you don't want to wait for an instance i.e. the constructor to return. Therefore, even if async constructors were possible, a constructor is not a place for long-running operations or starting background threads. The only purpose of a constructor is initialization of instance or class members to a default value or the captured constructor parameters. You always create the instance and then call DoSomething() on this instance. Async operations are no exception. You always defer expensive initialization of members.

There are a few solutions to avoid the requirement of async constructors.

  1. A simple alternative solution using Lazy<T> or AsyncLazy<T> (requires to install the Microsoft.VisualStudio.Threading package via the NuGet Package Manager). Lazy<T> allows to defer the instantiation or allocation of expensive resources.
public class OrderService
{
  public List<object> Orders => this.OrdersInitializer.GetValue();
  private AsyncLazy<List<object>> OrdersInitializer { get; }

  public OrderService()
    => this.OrdersInitializer = new AsyncLazy<List<object>>(InitializeOrdersAsync, new JoinableTaskFactory(new JoinableTaskContext()));

  private async Task<List<object>> InitializeOrdersAsync()
  {
    await Task.Delay(TimeSpan.FromSeconds(5));
    return new List<object> { 1, 2, 3 };
  }
}

public static void Main()
{
  var orderService = new OrderService();

  // Trigger async initialization
  orderService.Orders.Add(4);
}
  1. You can expose the data using a method instead of a property
public class OrderService
{
  private List<object> Orders { get; set; }

  public async Task<List<object>> GetOrdersAsync()
  {
    if (this.Orders == null)
    {
      await Task.Delay(TimeSpan.FromSeconds(5));
      this.Orders = new List<object> { 1, 2, 3 };
    }
    return this.Orders;
  }
}

public static async Task Main()
{
  var orderService = new OrderService();

  // Trigger async initialization
  List<object> orders = await orderService.GetOrdersAsync();
}
  1. Use an InitializeAsync method that must be called before using the instance
public class OrderService
{
  private List<object> orders;
  public List<object> Orders 
  { 
    get
    {
      if (!this.IsInitialized)
      {
        throw new InvalidOperationException(); 
      }
      return this.orders;
    }
    private set
    {
      this.orders = value;
    }
  }

  public bool IsInitialized { get; private set; }

  public async Task<List<object>> InitializeAsync()
  {
    if (this.IsInitialized)
    {
      return;
    }

    await Task.Delay(TimeSpan.FromSeconds(5));
    this.Orders = new List<object> { 1, 2, 3 };
    this.IsInitialized = true;
  }
}

public static async Task Main()
{
  var orderService = new OrderService();

  // Trigger async initialization
  await orderService.InitializeAsync();
}
  1. Instantiate the instance by passing the expensive arguments to the constructor
public class OrderService
{
  public List<object> Orders { get; }

  public async Task<List<object>> OrderService(List<object> orders)
    => this.Orders = orders;
}

public static async Task Main()
{
  List<object> orders = await GetOrdersAsync();

  // Instantiate with the result of the async operation
  var orderService = new OrderService(orders);
}

private static async Task<List<object>> GetOrdersAsync()
{
  await Task.Delay(TimeSpan.FromSeconds(5));
  return new List<object> { 1, 2, 3 };
}
  1. Use a factory method and a private constructor
public class OrderService
{
  public List<object> Orders { get; set; }

  private OrderServiceBase()  
    => this.Orders = new List<object>();

  public static async Task<OrderService> CreateInstanceAsync()
  {
    var instance = new OrderService();
    await Task.Delay(TimeSpan.FromSeconds(5));
    instance.Orders = new List<object> { 1, 2, 3 };
    return instance;
  }
}

public static async Task Main()
{
  // Trigger async initialization  
  OrderService orderService = await OrderService.CreateInstanceAsync();
}
Putnem answered 10/4, 2022 at 22:5 Comment(0)
W
0

Please bump this language request:

https://github.com/dotnet/csharplang/discussions/419

The amount of boilerplate code everyone needs to write to have a fully initialized async object is crazy and completely opposite of the trend in C# (less boilerplate).

Wariness answered 22/7, 2022 at 14:40 Comment(0)
B
0

Although it's not recommended to perform asynchronous tasks directly in a constructor, sometimes you might need a workaround.

A CancellationToken is used to set a time limit, helping avoid deadlocks.

However, this approach deviates from standard practices and should be used cautiously.

new SomeServiceUser(new());

public class SomeService
{
    public string? Data { get; set; }

    public SomeService()
    {
        // Using a CancellationToken to mitigate potential side effects of running an
        // asynchronous function in the constructor, such as preventing long waits
        // or unresponsive behavior by enabling a timeout for the async operation.
        var timeOutToken = new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token;

        var task = Task.Run(async () =>
        {
            Data = await GetDataAsync(timeOutToken); 
        });

        // Waiting for the asynchronous operation to complete before exiting the constructor.
        task.Wait();
    }

    async Task<string?> GetDataAsync(CancellationToken ct)
    {
        try
        {
            await Task.Delay(TimeSpan.FromSeconds(0.5), ct);
            return await Task.FromResult("Hello");
        }
        catch (OperationCanceledException)
        {
            return null;
        }
    }
}

public class SomeServiceUser
{
    readonly SomeService someService;

    public SomeServiceUser(SomeService someService)
    {
        this.someService = someService;
        Console.WriteLine(someService.Data); // "Hello"
    }
}
Berlin answered 26/1 at 7:29 Comment(0)
A
-1

The most upvoted, yet not accepted answer, can also be modified and improved imo.

What you could do is something like this instead :

public class ViewModel       
{       
    public TData Data { get; set; }

    private ViewModel() {}
      
    public static async Task<ViewModel> BuildViewModelAsync()  
    {       
        ViewModel vm = new ViewModel();
        vm.Data = await vm.GetDataTask(); 
        return vm;
    }       

    private async Task<TData> GetDataTask(){...}
}  
Abbreviation answered 1/6, 2023 at 16:5 Comment(1)
Duplicate of highly voted answers by Pierre and Harald. Just because the most correct answer isn't accepted is not a reason to add a redundant answer.Mitzi
G
-2

I would use something like this.

 public class MyViewModel
    {
            public MyDataTable Data { get; set; }
            public MyViewModel()
               {
                   loadData(() => GetData());
               }
               private async void loadData(Func<DataTable> load)
               {
                  try
                  {
                      MyDataTable = await Task.Run(load);
                  }
                  catch (Exception ex)
                  {
                       //log
                  }
               }
               private DataTable GetData()
               {
                    DataTable data;
                    // get data and return
                    return data;
               }
    }

This is as close to I can get for constructors.

Gynophore answered 17/4, 2017 at 19:3 Comment(0)
C
-2

you can create a wrapper and inject a functor representing the constructor:

class AsyncConstruct<T>
    where T: class
{
    private readonly Task<T> m_construction;
    private T m_constructed;
    public AsyncConstruct(Func<T> createFunc)
    {
        m_constructed = null;
        m_construction = Task.Run(()=>createFunc());
    }

    public T Get()
    {
        if(m_constructed == null)
        {
            m_constructed = m_construction.Result;
        }
        return m_constructed;
    }
}
Crosscurrent answered 9/6, 2022 at 7:10 Comment(0)
Z
-5

I use this easy trick.

public sealed partial class NamePage
{
  private readonly Task _initializingTask;

  public NamePage()
  {
    _initializingTask = Init();
  }

  private async Task Init()
  {
    /*
    Initialization that you need with await/async stuff allowed
    */
  }
}
Zulazulch answered 6/9, 2013 at 15:19 Comment(2)
Not finished when leaving constructorBagwell
your still not awaiting the return of the async so this is pointlessWouldst
G
-6

I'm not familiar with the async keyword (is this specific to Silverlight or a new feature in the beta version of Visual Studio?), but I think I can give you an idea of why you can't do this.

If I do:

var o = new MyObject();
MessageBox(o.SomeProperty.ToString());

o may not be done initializing before the next line of code runs. An instantiation of your object cannot be assigned until your constructor is completed, and making the constructor asynchronous wouldn't change that so what would be the point? However, you could call an asynchronous method from your constructor and then your constructor could complete and you would get your instantiation while the async method is still doing whatever it needs to do to setup your object.

Gib answered 16/11, 2011 at 1:29 Comment(4)
Moreover, what would it assign to o while it's waiting on the constructor to complete? I know the natural tendency is to think it should be null, but that's not how it works. You would never get null returned without threading... using threading doesn't change that.Gib
think about "var o;" only without "new MyObject()". that's what you get before constructor finishes its job. since making constructor async doesn't seem to be possible, we cannot test atomic times but we can assume it holds the same status with "var o;" only until it gets constructed.Conradconrade
'var o;' is not a valid statement. But let's assume we were specifying the type. In the first line you'd have 'object o;' and the second line would be 'o = new MyObject()'. Now, it HAS to assign something to o before it can go to the next line... there inlies the problem because it can't until the constructor is finished.Gib
it would return Task<MyObject>(), obviously.Poyssick

© 2022 - 2024 — McMap. All rights reserved.