Каков был бы самый элегантный способ вызова асинхронного метода из метода получения или установки в C #?
Вот некоторый псевдокод, чтобы объяснить себя.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
Task<T>
, которое будет возвращаться немедленно, иметь нормальную семантику свойств, и при этом все еще можно обрабатывать асинхронно при необходимости.Ответы:
Нет технической причины
async
свойства не разрешены в C #. Это было целенаправленное дизайнерское решение, потому что «асинхронные свойства» - это оксюморон.Свойства должны возвращать текущие значения; они не должны начинать фоновые операции.
Обычно, когда кто-то хочет «асинхронное свойство», он действительно хочет получить один из них:
async
метод.async
фабричный метод для содержащего объекта, либо используйтеasync InitAsync()
метод. Значение, привязанное к данным, будетdefault(T)
до тех пор, пока значение не будет вычислено / получено.AsyncLazy
из моего блога или библиотеки AsyncEx . Это даст вамawait
способную собственность.Обновление: я рассматриваю асинхронные свойства в одной из моих недавних публикаций в блоге "async OOP".
источник
Dispatcher.CurrentDispatcher.Invoke(new Action(..)
?INotifyPropertyChanged
, а затем решите, хотите ли вы вернуть старое значение илиdefault(T)
пока выполняется асинхронное обновление.NotifyTaskCompletion
моего проекта AsyncEx . Или вы можете построить свой собственный; это не так сложно.{Binding PropName.Result}
не тривиально для меня, чтобы узнать.Вы не можете вызывать его асинхронно, поскольку нет поддержки асинхронных свойств, только асинхронные методы. Таким образом, есть две опции, каждая из которых использует тот факт, что асинхронные методы в CTP - это на самом деле просто метод, который возвращает
Task<T>
илиTask
:Или:
источник
private async void SetupList() { MyList = await MyAsyncMethod(); }
этому. Это заставит MyList быть установленным (и затем автоматически связываться, если он реализует INPC), как только асинхронная операция завершится ...getTitle()
...Мне действительно нужно, чтобы вызов происходил из метода get из-за моей отделенной архитектуры. Поэтому я придумал следующую реализацию.
Использование: Заголовок находится в ViewModel или объекте, который вы можете статически объявить как ресурс страницы. Привязка к нему и значение будет заполнено без блокировки пользовательского интерфейса, когда getTitle () вернется.
источник
Я думаю, что мы можем подождать, пока значение вернет сначала значение null, а затем получит реальное значение, поэтому в случае Pure MVVM (например, проект PCL) я думаю, что наиболее элегантным решением является следующее:
источник
CS4014: Async method invocation without an await expression
async void
только для обработчиков верхнего уровня и тому подобное». Я думаю, что это может квалифицироваться как "и им нравится".Вы можете использовать
Task
как это:источник
Я думал, что .GetAwaiter (). GetResult () был именно этим решением, не так ли? например:
источник
.Result
- это не асинхронно и может привести к взаимоблокировке.Поскольку ваше «свойство async» находится в модели представления, вы можете использовать AsyncMVVM :
Он позаботится об уведомлении о контексте синхронизации и уведомлении об изменении свойства.
источник
Necromancing.
В .NET Core / NetStandard2 вы можете использовать
Nito.AsyncEx.AsyncContext.Run
вместоSystem.Windows.Threading.Dispatcher.InvokeAsync
:Если вы просто выбрали
System.Threading.Tasks.Task.Run
илиSystem.Threading.Tasks.Task<int>.Run
, то это не сработает.источник
Я думаю, что мой пример ниже может следовать подходу @ Stephen-Cleary, но я хотел бы привести закодированный пример. Это для использования в контексте привязки данных, например, Xamarin.
Конструктор класса - или, на самом деле, установщик другого свойства, от которого он зависит, - может вызвать асинхронную пустоту, которая заполнит свойство по завершении задачи без необходимости ожидания или блокировки. Когда он наконец получит значение, он обновит ваш пользовательский интерфейс с помощью механизма NotifyPropertyChanged.
Я не уверен в каких-либо побочных эффектах вызова aysnc void от конструктора. Возможно, комментатор остановится на обработке ошибок и т. Д.
источник
Когда я столкнулся с этой проблемой, попытка запустить синхронность асинхронных методов из установщика или конструктора привела меня в тупик в потоке пользовательского интерфейса, а использование обработчика событий потребовало слишком много изменений в общем проекте.
Решением было, как часто, было просто написать явно то, что я хотел, чтобы происходило неявно, а именно, чтобы другой поток обрабатывал операцию и чтобы основной поток ожидал ее завершения:
Можно утверждать, что я злоупотребляю фреймворком, но это работает.
источник
Я просматриваю все ответы, но у всех есть проблемы с производительностью.
например в:
Deployment.Current.Dispatcher.InvokeAsync (async () => {Title = await getTitle ();});
используйте диспетчер, который не является хорошим ответом.
но есть простое решение, просто сделайте это:
источник
Вы можете изменить свойство на
Task<IEnumerable>
и сделать что-то вроде:
и используйте его как ожидание MyList;
источник