我在Mac Mini上使用Xamarin Forms和Xamarin Studio,我有一个异步/等待问题,我希望有人可以提供帮助。我有一个按钮点击事件定义为:
void LoginButton_Clicked (object sender, EventArgs e)
{
//Do some stuff
this.HandleSignInCompleted(..);
}
然后调用一个方法进行一些用户配置文件初始化,它需要联系服务器:
async void HandleSignInCompleted(..)
{
var profile = await _profileService.GetAsync ().ConfigureAwait(false);
无论ConfigureAwait
是否存在,这都会无限期等待。用户配置文件服务简单地执行以下操作(只返回自己进行测试):
public async Task<UserProfile> GetAsync()
{
//wrapper around app properties
var accessToken = (string)_appProperties.Get ("token");
//Tried with ConfigureAwait and without
await Task.Delay (100);
//TODO:replace with facebook load
return new UserProfile (..);
}
ConfigureAwait(false)
,Task.Delay
窒息。没有它,它可以工作,但调试器崩溃了。发生了什么,如何解决这个问题,以便AJAX请求(当我将来在用户配置文件服务中替换它)时会有效?
答案 0 :(得分:2)
Sync-over-async是一个反模式;你不仅要接受自己的代码(必须在任何地方使用ConfigureAwait(false)
),而且还要受你所调用的任何库的支配。特别是,我过去在Xamarin上遇到过关于Task.Delay
的类似问题。在尝试将其切换为真正的网络呼叫之前,HttpClient
在某些移动平台(iOS或Android,不记得ATM)上存在同样的问题。不确定Facebook是否会有类似的错误。
因此,总而言之,你真的不能那样做。相反,一直拥抱async
:
async Task HandleSignInCompletedAsync(..)
{
var profile = await _profileService.GetAsync ().ConfigureAwait(false);
}
async void LoginButton_Clicked (object sender, EventArgs e)
{
//Do some stuff
await this.HandleSignInCompletedAsync(..);
}
如果必须,请禁用控件,但不要阻止。这种方法的一个很好的副作用是你的应用程序总是更具响应性。