我正在使用任务来执行大量的Web服务调用,并且想要在任何时候失败都要退出。这是我目前的代码:
service.Login(usernameTextField.Text, passwordTextField.Text).ContinueWith( t => {
if (t.IsFaulted){
new UIAlertView("Login Failed", "Unable to contact server at this time", null, "OK").Show();
} else {
if (t.Result)
{
service.GetImportantData ().ContinueWith (genericTask => {
if (genericTask.IsFaulted){
new UIAlertView("Login Failed", "Unable to contact server at this time", null, "OK").Show();
}
else {
service.SyncUserSpecificData().ContinueWith(projectTask => {
NavigationController.PopToRootViewController(true);
});
}
}, TaskScheduler.FromCurrentSynchronizationContext ());
} else {
new UIAlertView("Login Failed", "Please check your login and try again", null, "OK").Show();
}
}
loadingOverlay.Hide();
});
它是一个Xamarin应用程序,但这并不重要,因为我只是想知道是否有更好的方法来构建它们,包括错误检查,因为它目前是回调汤。
答案 0 :(得分:1)
我想说明你想要的流程是这样的:
static void DoSomething()
{
try
{
bool isLoggedIn = service.Login(usernameTextField.Text, passwordTextField.Text);
if(!isLoggedIn)
{
new UIAlertView("Login Failed",
"Please check your login and try again", null, "OK").Show();
return;
}
service.GetImportantData();
service.SyncUserSpecificData();
NavigationController.PopToRootViewController(true);
}
catch
{
new UIAlertView("Login Failed",
"Unable to contact server at this time", null, "OK").Show();
}
finally
{
loadingOverlay.Hide();
}
}
在这种情况下,我会像这样异步写它:
static void DoSomething()
{
service.Login(usernameTextField.Text, passwordTextField.Text)
.ContinueWith(task =>
{
bool isLoggedIn = task.Result;
if(!isLoggedIn)
{
new UIAlertView("Login Failed",
"Please check your login and try again", null, "OK").Show();
// this is just a dummy task to return without error.
return Task.FromResult(false);
}
return service.GetImportantData()
.ContinueWith(task2 =>
{
// do something with task2
task2.Wait(); // just forcing exceptions to be thrown.
return service.SyncUserSpecificData();
}).Unwrap()
.ContinueWith(task2 =>
{
// task2 is the result from SyncUserSpecificData().
task2.Wait(); // again just forcing exceptions to be thrown.
NavigationController.PopToRootViewController(true);
});
}).Unwrap()
.ContinueWith(task =>
{
new UIAlertView("Login Failed",
"Unable to contact server at this time", null, "OK").Show();
}, TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith(task =>
{
loadingOverlay.Hide();
});
}
这里有一些很大的不同:
首先,Unwrap()
用于构成一系列延续,而不会产生大量的嵌套调用。当您从续集中返回Task
时,会得到Task<Task>
,而Unwrap()
只返回内部Task
。这不是一个神奇的子弹,但它可能会非常强大。
其次,我让异常被抛出,而不是每次都动手检查IsFaulted
。当你致电Result
时,如果他们在那里就会被抛出。
第三,异常通过延续自然流动,直到最后进入单一延续。
答案 1 :(得分:1)
Xamarin支持async/await
关键字,您甚至可以创建支持此功能的可移植类库,如PCL and .NET NuGet Libraries are now enabled for Xamarin中所述。
这意味着您现在可以将Microsoft.Bcl.Async添加到项目中,即使在非MS平台上也可以使用async/await
。
使用async/await
,您可以像这样重写代码:
public async Task DoStuffAsync()
{
try
{
var success=await service.Login(usernameTextField.Text, passwordTextField.Text);
if(success)
{
var data=await service.GetImportantData();
await service.SyncUserSpecificData();
NavigationController.PopToRootViewController(true);
}
}
catch(WebException exc)
{
new UIAlertView("Login Failed", "Unable to contact server at this time", null, "OK").Show();
}
catch(Exception exc)
{
new UIAlertView("Login Failed", ex.Message, null, "OK").Show();
}
loadingOverlay.Hide();
}