2016-06-01 3 views
2

Lors de l'appel await RunAsync(); sur le code ci-dessous, je m'attendrais à la poursuite avec TaskContinuationOptions.OnlyRanToCompletion continuer à courir, mais la continuation OnlyOnCanceled est appelée (donnant la sortie de débogage "Tâche annulée").Pourquoi la suite OnlyOnCanceled est-elle appelée?

Pourquoi?

private static async Task RunAsync() 
{ 
    try 
    { 
     await Task.Run(() => DoWork()) 
      .ContinueWith(
       (t) => 
       { 
        if (t?.Exception != null) 
        { 
         throw t.Exception; 
        } 
       }, TaskContinuationOptions.OnlyOnFaulted 
      ).ContinueWith(
       (t) => 
       { 
        Debug.WriteLine("Task canceled."); 
       }, TaskContinuationOptions.OnlyOnCanceled 
      ).ContinueWith(
       (t) => 
       { 
        Debug.WriteLine("Task completed."); 
       }, TaskContinuationOptions.OnlyOnRanToCompletion); 

    } 
    catch (Exception ex) 
    { 
     Debug.WriteLine(ex.Message); 
    } 
} 

private static void DoWork() 
{ 
    Thread.Sleep(1000); 

} 

Répondre

4

Vous vous engagez sur vos suites erronées. Au lieu d'ajouter trois suites à la tâche "principale", vous ajoutez une continuation à une continuation à une continuation. Lorsque les tâches principales se terminent sans erreur, la suite OnlyOnFaulted est annulée, ce qui déclenche la poursuite OnlyOnCanceled vous incorrectement câblé à la suite OnlyOnFaulted au lieu de la tâche principale. Et puis la meilleure partie - cela signifie que la deuxième continuation s'est terminée correctement, et puisque vous avez câblé votre dernière continuation sur la deuxième continuation, la continuation finale s'exécute aussi, donc la sortie complète est "Tâche annulée. :)

Cependant, ce que vous attendez de la sortie n'est pas évident. Pourquoi utilisez-vous des poursuites en premier lieu? await gère pour vous beaucoup plus bien que vous ne pouvez jamais faire manuellement. Mélanger await et ContinueWith est rarement une bonne idée :) Essayez-vous await la tâche principale (échouer lorsqu'une exception est levée)? Ou l'une des suites? Ou juste la suite OnlyOnRanToCompletion (c'est ce que vous faites en ce moment, et ça ne marchera jamais comme vous l'attendez)? Et si cette suite n'a jamais une chance de courir?