Task continuations always run even when specifying

2019-06-24 03:02发布

问题:

I want to run some code when an async task completes successfully.

From reading documentation and examples on the web, I thought I could use Task.ContinueWith and specify TaskContinuationOptions.OnlyOnRanToCompletion.

However, this doesn't behave as I expected.

The following code is a console program, created in Visual Studio 2012, .Net 4.5:

using System;
using System.Threading.Tasks;

namespace TaskContinueTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var jobTask = Task.Factory.StartNew(() => { });

            jobTask.ContinueWith((task, options) =>
            {
                Console.WriteLine("Completed handler. Task status is {0}", task.Status);
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            jobTask.ContinueWith((task, options) =>
            {
                Console.WriteLine("Faulted handler. Task status is {0}", task.Status);
            }, TaskContinuationOptions.OnlyOnFaulted);

            Console.ReadLine();
        }
    }
}

when run, I get the output:

Completed handler. Task status is RanToCompletion
Faulted handler. Task status is RanToCompletion

which is very surprising (at least to me). Why are both continuations scheduled?

I get the same behavior if I throw an exception in jobTask, but the output is now:

Completed handler. Task status is Faulted
Faulted handler. Task status is Faulted

So the framework clearly knows the status of the task, but why are both continuations still scheduled?

回答1:

I think the problem is that you're accidentally calling this overload

public Task ContinueWith(
    Action<Task, Object> continuationAction,
    Object state
)

What you want is this overload:

public Task ContinueWith(
    Action<Task> continuationAction,
    TaskContinuationOptions continuationOptions
)

You just need to change your lambda expressions to use a single parameter:

Task.ContinueWith(task => Console.WriteLine(...),
    TaskContinuationOptions.OnlyOnRanToCompletion);