2013-11-27 67 views
0

我正在使用任務來執行多個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應用程序,但認爲不應該的問題,因爲我只是想知道有沒有更好的方式來撰寫他們包括錯誤檢查,因爲它的回調湯的時刻。

+1

我想你不能使用C#5? –

+0

您究竟希望TPL知道什麼是「撤消」由成功執行的任務所做的更改所必需的? –

+0

@CoryNelson我認爲Xamarin有異步/等待,如果這就是你所追求的,你有什麼機會向我展示這將如何改善? – RodH257

回答

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

Xamarin確實支持async/await關鍵字,您甚至可以創建支持該關鍵字的Portable Class Libraries,如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(); 
}