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

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。可能有很多(甚至明显的)边缘情况和理由反对它,我只是想不出任何一个。我也四处寻找解释,但似乎找不到任何解释。


当前回答

其中一些答案涉及创造一种新的公共方法。不这样做,使用Lazy<T>类:

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

要使用Data,请使用Data. value。

其他回答

你可以创建一个包装器并注入一个表示构造函数的函子:

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

我用这个简单的技巧。

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
    */
  }
}

你可以在构造函数中使用Action

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

我不熟悉async关键字(这是针对Silverlight还是Visual Studio测试版的新功能?),但我想我可以告诉你为什么不能这样做。

如果我这样做:

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

在运行下一行代码之前,O可能无法完成初始化。在构造函数完成之前,不能分配对象的实例化,并且使构造函数异步不会改变这一点,那么重点是什么呢?然而,你可以从你的构造函数调用一个异步方法,然后你的构造函数就可以完成,你就可以在async方法仍然在做它需要做的事情来设置你的对象的时候得到你的实例化。

我会用这样的东西。

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

这是我能得到的最接近构造函数的值。