Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Task ContinueWith only if completed successfully

Posted by Ricibald on December 6th, 2015

Task ContinueWith only if completed successfully

When a Task is canceled it propagates a TaskCanceledException that can be handled using ContinueWith:


var tcs = new TaskCompletionSource<int> ();
tcs.SetCanceled ();


Task.Run (async () => await tcs.Task)
    .ContinueWith(antecedent => Console.WriteLine("Finalize my work"))
    .Wait();

// OUTPUT:
// Finalize my work


The problem is that ContinueWith works in these cases:

  • the task is completed successfully
  • the task is canceled (TaskCanceledException)
  • the task is faulted (Exception or AggregateException)

In other words ContinueWith is the finally part in a try/catch block.

For me it seems a little weird, it would sounds better to continue only in case of success.

You can continue only in case of success chaining the different cases in this way according to TPL guide:

var tcs = new TaskCompletionSource<int> ();
  
tcs.SetCanceled ();

   

Task.Run (async () => await tcs.Task)

    .ContinueWith(antecedent => Console.WriteLine("Finalize my work"), TaskContinuationOptions.OnlyOnRanToCompletion)

    .ContinueWith(antecedent => Console.WriteLine("Undo my work"), TaskContinuationOptions.OnlyOnCanceled)

    .ContinueWith(antecedent => Console.WriteLine("Abort my work"), TaskContinuationOptions.OnlyOnFaulted)

    .ContinueWith(antecedent => Console.WriteLine("Clean resources (finally part)")
    .Wait();

// OUTPUT:
// Undo my work
// Clean resources (finally part)


You can finally write your extension method to have this behavior compact and readable:

var tcs = new TaskCompletionSource<int> ();
  
tcs.SetCanceled ();

   

Task.Run (async () => await tcs.Task)
        
    .ContinueOnlyOnSuccessWith (antecedent => Console.WriteLine ("Finalize my work"))

    .Wait();
 

// OUTPUT:
// <empty>


This is the code for ContinueOnlyOnSuccessWith:

public static class Extensions
{
        
    /// <summary>
    
    /// Continues only if task is completed successfully.
        
    /// It handles the cancelled and failed state.

    /// </summary>
       
    public static Task ContinueOnlyOnSuccessWith(this Task task, Action<Task> continuationAction) 
    {
            
        return task
              
            .ContinueWith (continuationAction, TaskContinuationOptions.OnlyOnRanToCompletion)

            .ContinueWith(antecedent => {});
     
    }
}

Leave a Reply

You must be logged in to post a comment.