Могут ли конструкторы быть асинхронными? - PullRequest
231 голосов
/ 16 ноября 2011

У меня есть проект, в котором я пытаюсь заполнить некоторые данные в конструкторе:

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 из конструктора напрямую. Вероятно, есть много (даже очевидных) крайних случаев и причин против этого, я просто не могу думать ни о каком. Я также ищу объяснения, но не могу найти ни одного.

Ответы [ 13 ]

0 голосов
/ 06 сентября 2013

Я использую этот легкий трюк.

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
    */
  }
}
0 голосов
/ 20 марта 2013

Вы можете использовать Действие внутри Конструктора

 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;
        }
    }
0 голосов
/ 16 ноября 2011

Я не знаком с ключевым словом async (это специфично для Silverlight или новой функции в бета-версии Visual Studio?), Но я думаю, что могу дать вам представление о том, почему вы не можете этого сделать.

Если я это сделаю:

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

o нельзя выполнить инициализацию до запуска следующей строки кода. Инстанцирование вашего объекта не может быть назначено до тех пор, пока ваш конструктор не будет завершен, и создание асинхронного конструктора не изменит это, так какой в ​​этом смысл? Однако вы можете вызвать асинхронный метод из вашего конструктора, а затем ваш конструктор может завершиться, и вы получите свою реализацию, пока асинхронный метод все еще делает все, что нужно для настройки вашего объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...