Что не так с TaskCompletionSource <DeploymentCatalog>? - PullRequest
0 голосов
/ 02 марта 2012

Я использую пакет Nuget System.Threading.Tasks для Silverlight 4 (порт из Mono). Я продолжаю получать InvalidOperationException («Основная задача уже находится в одном из трех конечных состояний: RanToCompletion, Failed или 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() явно задавать задачи - однако я не тестировал WebClient с монопортовой версией Task Parallel Библиотека (для Silverlight). Думаю, мне следует это сделать ...

Ответы [ 2 ]

3 голосов
/ 02 марта 2012

Вы вызываете Start для TaskCompletionSource, и задача TCS уже запущена, а в случае, когда вы получаете это исключение, она также уже выполнена.Как правило, вы хотите разработать методы, такие как DownloadCatalogAsTask, для возврата уже запущенных экземпляров задач, и вызывающие стороны могут ожидать их запуска и избегать вызова Start самостоятельно.

Пара других предложений:

  1. Я бы рассмотрелпереименование метода в DownloadCatalogAsync для согласования с правилами именования в .NET 4.5.
  2. Я бы не стал передавать Action <> в асинхронный метод.Весь смысл возврата Задачи состоит в том, что вы можете связывать продолжения, используя знакомые шаблоны, такие как явный ContinueWith или ключевое слово await в C # 5.0.Здесь вы изобретаете свой собственный подход.
0 голосов
/ 25 апреля 2012

У меня была такая же проблема. то есть Mono TPL на Silverlight 4; исключение выдано на completionSource.SetResult().

Это было решено, когда я использовал completionSource.TrySetResult().

...