2012-03-02 61 views
0

我爲Silverlight 4(Mono的一個端口)使用Nuget包System.Threading.Tasks。我不斷收到InvalidOperationException(「基礎任務已經在三個最終狀態之一:RanToCompletion,斷陷,或取消」)以下:TaskCompletionSource <DeploymentCatalog>有什麼問題?

var tasks = new Task<DeploymentCatalog>[2]; 

//Catalog the XAP downloaded by the Application Loader, the BiggestBox Index: 
var uri0 = new Uri(Application.Current. 

Host.InitParams["LoaderInfoXapPath"], UriKind.Relative); 
tasks[0] = CompositionUtility.DownloadCatalogAsync(uri0); 

//Catalog the XAP with the BiggestBox Index Part: 
var uri1 = new Uri(Application.Current 
    .Host.InitParams["BiggestBoxIndexXapPath"], UriKind.Relative); 
tasks[1] = CompositionUtility.DownloadCatalogAsync(uri1); 

//tasks did not run by default... 
//tasks[0].Start(); 
//tasks[1].Start(); 

Task.WaitAll(tasks); 

this.AddToAggregateCatalog(tasks[0].Result); 
this.AddToAggregateCatalog(tasks[1].Result); 

base.Compose(); 

其中DownloadCatalogAsync是:

/// <summary> 
/// Downloads the catalog 
/// in a <see cref="System.Threading.Task"/>. 
/// </summary> 
/// <param name="location">The location.</param> 
/// <param name="downloadCompleteAction">The download complete action.</param> 
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", 
    Justification = "Reliable disposal depends on callers.")] 
public static Task<DeploymentCatalog> DownloadCatalogAsync(Uri location) 
{ 
    return DownloadCatalogAsTask(location, null); 
} 

/// <summary> 
/// Downloads the catalog 
/// in a <see cref="System.Threading.Task"/>. 
/// </summary> 
/// <param name="location">The location.</param> 
/// <param name="downloadCompleteAction">The download complete action.</param> 
/// <remarks> 
/// For details, see the 「Converting an Event-Based Pattern」 section in 
/// 「Simplify Asynchronous Programming with Tasks」 
/// by Igor Ostrovsky 
/// [http://msdn.microsoft.com/en-us/magazine/ff959203.aspx] 
/// </remarks> 
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", 
    Justification = "Reliable disposal depends on callers.")] 
public static Task<DeploymentCatalog> DownloadCatalogAsync(Uri location, 
    Action<object, AsyncCompletedEventArgs> downloadCompleteAction) 
{ 
    var completionSource = new TaskCompletionSource<DeploymentCatalog>(); 
    var catalog = new DeploymentCatalog(location); 

    catalog.DownloadCompleted += (s, args) => 
    { 
     if(args.Error != null) completionSource.SetException(args.Error); 
     else if(args.Cancelled) completionSource.SetCanceled(); 
     else 
     { 
      completionSource.SetResult(s as DeploymentCatalog); //exception thrown here 
      if(downloadCompleteAction != null) 
       downloadCompleteAction.Invoke(s, args); 
     } 
    }; 

    catalog.DownloadAsync(); 

    return completionSource.Task; 
} 

我使用這種模式與WebClient和它工作正常(但我沒有Start()明確的任務---但我沒有測試WebClient與單端口版本的任務並行庫(用於Silverlight)。我應該這樣做...

回答

3

您在TaskCompletionSource上調用Start,並且TCS Task已經啓動,並且在出現此異常的情況下,它也已經完成。通常,您希望設計諸如DownloadCatalogAsTask之類的方法來返回已啓動的Task實例,並且調用者可以期望它們啓動並避免調用Start自己。

夫婦的其他建議:

  1. 我會考慮重新命名方法DownloadCatalogAsync與.NET 4.5命名規則一致。
  2. 我不會將Action <>傳入異步方法。返回任務的重點在於,您可以使用熟悉的模式(如C#5.0中的顯式ContinueWith或await關鍵字)連續進行連續操作。在這裏,你正在創造你自己的方法。
+0

我會把這些新的4.5公約放在心上。我沒有提到我使用帶有TPL Mono端口的Silverlight 4。不幸的是,我不得不明確地調用'Start()',否則任務會返回'WaitingForActivation' - 這種意外的行爲可能與這個Mono的東西有關? – rasx 2012-03-02 17:58:03

+0

@rasx可以的,你必須調用Start,只要確保在返回Task的方法內啓動它,而不是將它留給消費者來啓動它。就行爲而言,是的,這是因爲您必須採用Silverlight + Mono TPL庫的方法。在.NET 4 TPL中,你更可能使用Task.Factory.StartNew。 – 2012-03-05 19:44:26

0

我有同樣的問題。即Silverlight 4上的Mono TPL;拋出異常completionSource.SetResult()

這個問題在我用completionSource.TrySetResult()代替時解決了。