为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
德玛西亚99 2019-07-13 10:47:23
我有一个项目,我试图在构造函数中填充一些数据: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直接从构造函数中删除。可能有很多(甚至明显的)边缘情况和反对它的理由,我只是想不出任何。我也四处寻找解释,但似乎找不到任何解释。
查看完整描述

3 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

构造函数的作用非常类似于返回构造类型的方法。和async方法不能返回任何类型,它必须是“火而忘”。void,或Task.

如果类型的构造函数T实际上回来了Task<T>,我想这会让人很困惑。

如果异步构造函数的行为方式与async void方法,这种类型破坏了构造函数的意义。构造函数返回后,您应该得到一个完全初始化的对象。而不是将来在某个未定义的点上被正确初始化的对象。也就是说,如果幸运的话,异步初始化不会失败。

这一切只是猜测而已。但在我看来,拥有异步构造函数的可能性会带来更多的麻烦。

如果你真的想要的“火和忘记”语义学async void方法(如果可能的话,应该避免),您可以轻松地将所有代码封装在async void方法,并从构造函数中调用它,正如您在问题中提到的那样。


查看完整回答
反对 回复 2019-07-13
?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

由于不可能创建异步构造函数,所以我使用了一个静态异步方法,该方法返回由私有构造函数创建的类实例。这不雅致,但效果不错。

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


查看完整回答
反对 回复 2019-07-13
?
蛊毒传说

TA贡献1895条经验 获得超3个赞

您的问题类似于创建文件对象和打开文件。实际上,在实际使用对象之前,有很多类需要执行两个步骤:Create+Initialization(通常称为类似于Open)。

它的优点是构造函数可以是轻量级的。如果需要,可以在实际初始化对象之前更改一些属性。设置所有属性时,Initialize/Open函数来准备要使用的对象。这,这个Initialize函数可以是异步的。

缺点是您必须信任您的类的用户,他将调用该用户。Initialize()在他使用你类的任何其他函数之前。事实上,如果你想让你的课充分证明(傻瓜证明?)您必须签入每个函数Initialize()已经被召唤了。

使这更容易的模式是声明构造函数私有,并使一个公共静态函数来构造对象并调用。Initialize()在返回构造的对象之前。这样,您就会知道每个访问对象的人都使用了Initialize功能。

该示例显示了一个类,该类模拟所需的异步构造函数。

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 OtherFunctionAsync(a, b);
    }

使用情况如下:

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


查看完整回答
反对 回复 2019-07-13
  • 3 回答
  • 0 关注
  • 610 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信