TaskCompletionSource <deploymentcatalog>?</deploymentcatalog>有什么问题

时间:2012-03-02 07:54:00

标签: c# silverlight-4.0 mono mef task-parallel-library

我正在使用Nuget包System.Threading.Tasks用于Silverlight 4(来自Mono的端口)。我一直得到InvalidOperationException(“基础任务已经处于三个最终状态之一:RanToCompletion,Faulted或Cancelled。”)以下内容:

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()任务 - 但是我没有使用Mono测试WebClient任务并行库(适用于Silverlight)的移植版本。我想我应该这样做......

2 个答案:

答案 0 :(得分:3)

您正在调用TaskCompletionSource上的Start并且TCS任务已经启动,并且在您遇到此异常的情况下,它也已经完成。通常,您希望设计像DownloadCatalogAsTask这样的方法来返回已经启动的Task实例,并且调用者可以期望它们启动并避免自己调用Start。

结合其他建议:

  1. 我会考虑将方法重命名为DownloadCatalogAsync以符合.NET 4.5命名准则。
  2. 我不会通过动作&lt;&gt;进入异步方法。返回Task的重点是,您可以使用熟悉的模式(如显式的ContinueWith或C#5.0中的await关键字)链接continuation。在这里,你发明了自己的方法。

答案 1 :(得分:0)

我遇到了同样的问题。即Silverlight 4上的Mono TPL; completionSource.SetResult()引发的异常。

当我使用completionSource.TrySetResult()时,这已得到解决。