2012-03-06 51 views
7

處理我有以下結構的方法:任務組成和誤差TPL

public Task InitializeAsync() 
{ 
    var taskCompletionSource = new TaskCompletionSource<bool>(); 

    Task firstTask = ...; 

    // secondTask calls taskCompletionSource.TrySetResult(true) once it considers itself "done" 
    Task secondTask = firstTask.ContinueWith(..., TaskContinuationOptions.OnlyOnRanToCompletion); 

    Action<TasK> errorContinuation = x => 
     { 
      taskCompletionSource.SetException(e.Exception); 
     }; 

    firstTask.ContinueWith(errorContinuation, TaskContinuationOptions.OnlyOnFaulted); 
    secondTask.ContinueWith(errorContinuation, TaskContinuationOptions.OnlyOnFaulted); 

    return taskCompletionSource.Task; 
} 

重要:

  • InitializeAsync返回的任務不認爲是完整的,直到secondTask決定這樣
  • secondTask僅當firstTask成功時才運行
  • 任一故障firstTasksecondTask導致整個任務失敗

什麼我不知道是是否有一個更清潔,更簡單的表達,一面實現相同的功能的方式。我使用的是.NET 4.0,但對4.5是否更容易使用感興趣。

+1

在4.5中,您可以通過await/async功能執行此操作,並通過在異步函數內部一起插入任務來嘗試/捕獲 – Carsten 2012-03-06 16:48:33

+0

我最近遇到了同樣的問題,並沿着相同的路線前進,直到找到Stephen的博客文章Toub Gideon的答案鏈接到。它比我最初嘗試解決方案時更清晰,更明顯地處理所有的角落案例。 – shambulator 2012-03-08 15:49:35

回答

5

對於.NET 4.0,我用了一個想法從this blog article到連鎖的任務像你描述。尤其要看然後。這並不是說他的版本希望你在返回任務的函數傳遞,而不是僅僅通過像使用方法ContinueWith

順便說一句,Then讓你很接近SelectMany你需要能夠鏈通過LINQ從子句執行任務。我主要提到這是一個語法選項,直到.NET 4.5中的異步/等待,儘管我自己並沒有真正使用它。

+0

這是一個乾淨的通用解決方案,我很驚訝不在BCL中,儘管'TaskCompletionSource'確實使它足夠簡單並且可以實現。如果你想要一個更像'ContinueWith'的簽名,你必須提供指定取消標記,調度程序等的重載。 – shambulator 2012-03-08 15:47:38

+1

這是我理解的需要填充的確切空洞。非常感謝。 – 2012-03-08 16:49:29