一尘不染

构造函数可以异步吗?

c#

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

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直接在构造函数中调用。可能有很多(甚至很明显)极端的情况和反对的理由,我只是想不到。我也在四处寻找解释,但似乎找不到任何解释。


阅读 466

收藏
2020-05-19

共1个答案

一尘不染

构造函数的行为与返回构造类型的方法非常相似。而且asyncmethod不能返回任何类型,它必须是“ fire and忘记” voidTask

我认为,如果类型的构造函数T实际返回了Task<T>,那将非常令人困惑。

如果异步构造函数的行为与方法相同,则将async void破坏构造函数的含义。构造函数返回后,您应该获得一个完全初始化的对象。不是将来会在某个不确定的位置正确初始化的对象。也就是说,如果您很幸运并且异步初始化不会失败。

所有这些只是一个猜测。但是在我看来,异步构造函数的可能性带来的麻烦多于其价值。

如果您确实想要方法的“即弃即用”语义async void(如果可能,应避免使用),则可以轻松地将所有代码封装在async void方法中,并从构造函数中调用它,如您在问题中提到的那样。

2020-05-19