Creating a continuation Task
that has a result of different type than the first task, with ContinueWith
, is not trivial. You have to use the Unwrap
method in order to flatten the resulting Task<Task<MySecondResult>>
, handle carefully the failure and cancellation cases, and specify explicitly the TaskScheduler
that will execute the continuation:
Task<MySecondResult> task = GetFirstResultAsync().ContinueWith(t =>
{
if (t.IsFaulted)
{
var tcs = new TaskCompletionSource<MySecondResult>();
tcs.SetException(t.Exception.InnerExceptions);
return tcs.Task;
}
if (t.IsCanceled)
{
TaskCompletionSource<MySecondResult> tcs = new();
tcs.SetCanceled(new TaskCanceledException(t).CancellationToken);
return tcs.Task;
}
return GetSecondResultAsync(t.Result);
}, TaskScheduler.Default).Unwrap();
This is quite cumbersome. You don't want to have code like this appear frequently in your application code. You can either encapsulate this functionality in an extension method, like the Then
/ContinueWithResult
extension method requested in this GitHub proposal, or use async/await instead of the ContinueWith
. Async/await is composable, so you can write a third async
method that combines the GetFirstResultAsync
and the GetSecondResultAsync
to one:
async Task<MySecondResult> GetSecondAfterFirstAsync()
{
MyFirstResult result = await GetFirstResultAsync();
return await GetSecondResultAsync(result);
}