构造函数可以是异步的吗?

我有一个项目,我试图在构造函数中填充一些数据:

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;
    }}

不幸的是,我收到了一个错误:

改性剂async对此项目无效。

当然,如果我包装一个标准方法并从构造函数调用它:

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

效果很好。同样的,如果我用旧的内出方式

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

这也很管用。我只是想知道为什么我们不能打电话await直接从构造函数中删除。可能有很多(甚至明显的)边缘情况和反对它的理由,我只是想不出任何。我也四处寻找解释,但似乎找不到任何解释。


函数式编程
浏览 635回答 3
3回答

狐的传说

构造函数的作用非常类似于返回构造类型的方法。和async方法不能返回任何类型,它必须是“火而忘”。void,或Task.如果类型的构造函数T实际上回来了Task<T>,我想这会让人很困惑。如果异步构造函数的行为方式与async void方法,这种类型破坏了构造函数的意义。构造函数返回后,您应该得到一个完全初始化的对象。而不是将来在某个未定义的点上被正确初始化的对象。也就是说,如果幸运的话,异步初始化不会失败。这一切只是猜测而已。但在我看来,拥有异步构造函数的可能性会带来更多的麻烦。如果你真的想要的“火和忘记”语义学async void方法(如果可能的话,应该避免),您可以轻松地将所有代码封装在async void方法,并从构造函数中调用它,正如您在问题中提到的那样。

慕运维8079593

由于不可能创建异步构造函数,所以我使用了一个静态异步方法,该方法返回由私有构造函数创建的类实例。这不雅致,但效果不错。&nbsp;&nbsp;&nbsp;public&nbsp;class&nbsp;ViewModel&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;ObservableCollection<TData>&nbsp;Data&nbsp;{&nbsp;get;&nbsp;set;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//static&nbsp;async&nbsp;method&nbsp;that&nbsp;behave&nbsp;like&nbsp;a&nbsp;constructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;async&nbsp;public&nbsp;static&nbsp;Task<ViewModel>&nbsp;BuildViewModelAsync()&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ObservableCollection<TData>&nbsp;tmpData&nbsp;=&nbsp;await&nbsp;GetDataTask();&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;ViewModel(tmpData); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;private&nbsp;constructor&nbsp;called&nbsp;by&nbsp;the&nbsp;async&nbsp;method &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;ViewModel(ObservableCollection<TData>&nbsp;Data) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.Data=Data;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;}

缥缈止盈

您的问题类似于创建文件对象和打开文件。实际上,在实际使用对象之前,有很多类需要执行两个步骤:Create+Initialization(通常称为类似于Open)。它的优点是构造函数可以是轻量级的。如果需要,可以在实际初始化对象之前更改一些属性。设置所有属性时,Initialize/Open函数来准备要使用的对象。这,这个Initialize函数可以是异步的。缺点是您必须信任您的类的用户,他将调用该用户。Initialize()在他使用你类的任何其他函数之前。事实上,如果你想让你的课充分证明(傻瓜证明?)您必须签入每个函数Initialize()已经被召唤了。使这更容易的模式是声明构造函数私有,并使一个公共静态函数来构造对象并调用。Initialize()在返回构造的对象之前。这样,您就会知道每个访问对象的人都使用了Initialize功能。该示例显示了一个类,该类模拟所需的异步构造函数。public&nbsp;MyClass{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;async&nbsp;Task<MyClass>&nbsp;CreateAsync(...) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyClass&nbsp;x&nbsp;=&nbsp;new&nbsp;MyClass(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;await&nbsp;x.InitializeAsync(...) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;make&nbsp;sure&nbsp;no&nbsp;one&nbsp;but&nbsp;the&nbsp;Create&nbsp;function&nbsp;can&nbsp;call&nbsp;the&nbsp;constructor: &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;MyClass(){} &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;async&nbsp;Task&nbsp;InitializeAsync(...) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;do&nbsp;the&nbsp;async&nbsp;things&nbsp;you&nbsp;wanted&nbsp;to&nbsp;do&nbsp;in&nbsp;your&nbsp;async&nbsp;constructor &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;async&nbsp;Task<int>&nbsp;OtherFunctionAsync(int&nbsp;a,&nbsp;int&nbsp;b) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;await&nbsp;OtherFunctionAsync(a,&nbsp;b); &nbsp;&nbsp;&nbsp;&nbsp;}使用情况如下:public&nbsp;async&nbsp;Task<int>&nbsp;SomethingAsync(){ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Create&nbsp;and&nbsp;initialize&nbsp;a&nbsp;MyClass&nbsp;object &nbsp;&nbsp;&nbsp;&nbsp;MyClass&nbsp;myObject&nbsp;=&nbsp;await&nbsp;MyClass.CreateAsync(...); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;use&nbsp;the&nbsp;created&nbsp;object: &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;await&nbsp;myObject.OtherFunctionAsync(4,&nbsp;7);}
打开App,查看更多内容
随时随地看视频慕课网APP