Pantelis
Pantelis

Reputation: 2070

Prevent a Task Continuation

I'm using Task continuations for a long running operation on a WinForm project.

var task1 = Task.Factory.StartNew(() => DoSomeWork());

var task2 = task1.ContinueWith(result => DoSomeMoreWork(), TaskContinuationOptions.OnlyOnRanToCompletion);

var task3 = task2.ContinueWith(result => DoFinalWork(), TaskContinuationOptions.OnlyOnRanToCompletion);

I only want to continue to task3 if some conditions are met on the DoSomeMoreWork() function that executes on task2. How can this be done?

Upvotes: 2

Views: 1025

Answers (2)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131748

Another option is to convert task2 and task3 to nested tasks, executing them only if a condition is met.

Assuming DoSomeMoreWork returns true to do this, you could write something like this

        var task1 = Task.Factory.StartNew(DoSomeWork);
        var task2 = task1.ContinueWith(result =>
            {
                if (DoSomeMoreWork())
                {
                    Task.Factory.StartNew(DoFinalWork, TaskCreationOptions.AttachedToParent);
                }
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

If you can use the Async CTP or .NET 4.5 (I think both have a Go Live license), you can replace the continuations with async/await for much cleaner code.

If you convert the worker functions to use async, your code becomes almost as clear as the synchronous version:

    private static async void WorkAsync()
    {
        await DoSomeWork();
        if (await DoSomeMoreWork())
        {
            await DoFinalWork();
        }
    }

    private static async Task DoFinalWork()
    {
        Console.WriteLine("Completed");
    }

    private static async Task<bool> DoSomeMoreWork()
    {
        Console.WriteLine("Some More");
        return true;
    }

    private static async Task DoSomeWork()
    {
        Console.WriteLine("Some");
    }

If you don't want to return Tasks from the methods, you can use the following code:

    private static async void WorkAsync()
    {
        await Task.Run(()=>DoSomeWork());
        if (await Task.Run(()=>DoSomeMoreWork()))
        {
            await Task.Run(()=>DoFinalWork());
        }
    }

Upvotes: 1

Peter Kelly
Peter Kelly

Reputation: 14411

From MSDN

a user-defined value can be passed from the antecedent to its continuation in the Result property, so that the output of the antecedent can serve as input for the continuation

So one way would be in task3, check the Result from task2 before doing any work.

var task2 = task1.ContinueWith(result => DoSomeMoreWOrk(), TaskContinuationOptions.OnlyOnRanToCompletion);
var task3 = task2.ContinueWith(x => DoFinalWork(x.Result));

Where the Result returned from task2 determines what happens in task3.

EDIT Another solution would be to cancel task2 if certain conditions are not met within the operation. Then the continuation task is not even scheduled.

From MSDN

To prevent a continuation from executing if its antecedent is canceled, specify the NotOnCanceled option when you create the continuation.

So task3 definition becomes

var task3 = task2.ContinueWith(result => DoFinalWork(), TaskContinuationOptions.NotOnCancelled);

Upvotes: 1

Related Questions