Marius
Marius

Reputation: 1062

Continue with a method that returns a task

I would like to execute three steps of work. One prepare task, one work task that is encapsulated in a method returning a task and a clean up task that requires results from the previous step. But I am not sure whether I did it the proper way with unwrapping and accessing the 'Result' property or if there is cleaner version of including the method in the execution chain.

static void Main(string[] args)
{
    Task.Factory.StartNew(() => Console.WriteLine("Prepare"))
                .ContinueWith(x => Work())
                .ContinueWith(x => Console.WriteLine(x.Unwrap().Result));
    Console.ReadLine();
}

private static Task<string> Work()
{
    Thread.Sleep(1500);
    return Task.Factory.StartNew(() => "See my results...");
}

Upvotes: 4

Views: 2293

Answers (2)

Sam Harwell
Sam Harwell

Reputation: 99859

If you use the Rackspace Threading Library, it's easy to ensure operations are performed with the desired semantics. In addition, it handles canceled and faulted tasks in predictable ways (a daunting feat when you aren't using async/await, to say the least).

  • Use Select for continuations that do not return a Task (either a value, or void)
  • Use Then for continuations that return a Task or Task<T>

Example:

static void Main(string[] args)
{
    Task operation = Task.Factory.StartNew(() => Console.WriteLine("Prepare"))
        .Then(_ => WorkAsync())
        .Select(resultTask => Console.WriteLine(resultTask.Result));
    operation.Wait();
    Console.ReadLine();
}

private static Task<string> WorkAsync()
{
    return DelayedTask.Delay(TimeSpan.FromMilliseconds(1500))
        .Select(_ => "See my results...");
}

If you still want to use the TPL directly, then the main problem (aside from cancellation and exception handling) with the original code is the placement of the call to Unwrap. You actually would want to place it as you see in this code:

// NOTE: I WOULD NOT USE THIS CODE
// (preferring the Threading Library or async/await instead)
static void Main(string[] args)
{
    Task.Factory.StartNew(() => Console.WriteLine("Prepare"))
                .ContinueWith(x => Work()).Unwrap()
                .ContinueWith(x => Console.WriteLine(x.Result));
    Console.ReadLine();
}

Upvotes: 1

i3arnon
i3arnon

Reputation: 116518

You can simply have an async method that executes all the steps and returns a Task:

static async Task DoAsync()
{
    Console.WriteLine("Prepare");
    Console.WriteLine(await WorkAsync());
}

static void Main(string[] args)
{
    DoAsync().Wait();
    Console.ReadLine();
}

Upvotes: 2

Related Questions