Search code examples
c#async-awaittasktask-parallel-library

Return new task with return value, using the Task constructor with async action


Maybe someone can explain, why this is working:

var task = new Task(async () =>
{
    var noSolution = await AsyncMethodWithBoolReturnValue();

    if (noSolution)
    {
        await DoSomethingAsync();
    }
});

But using the generic to specify the return value is not possible?

var task = new Task<bool>(async () =>
{
    var noSolution = await AsyncMethodWithBoolReturnValue();

    if (noSolution)
    {
        await DoSomethingAsync();
    }

    return noSolution;
});

Thanks a lot!


Solution

  • The non-generic Task constructor is not async-friendy. The async delegate is async void. What you really want is probably a nested Task<Task>. This is a Task that represents the creation of another Task. When the outer Task completes, it means that the inner Task has been created:

    Task<Task> taskTask = new(async () =>
    {
        bool noSolution = await AsyncMethodWithBoolReturnValue();
    
        if (noSolution)
        {
            await DoSomethingAsync();
        }
    });
    

    Or with result:

    Task<Task<bool>> taskTask = new(async () =>
    {
        bool noSolution = await AsyncMethodWithBoolReturnValue();
    
        if (noSolution)
        {
            await DoSomethingAsync();
        }
    
        return noSolution;
    });
    

    You can then use the Unwrap method, to create a new proxy Task that represents the completion of both the outer and inner tasks. I don't know what exactly you want to do, but most likely you will need this.

    Also make sure that when you Start/RunSynchronously the taskTask, you specify explicitly the TaskScheduler, so that your code complies with the CA2008 guideline:

    taskTask.RunSynchronously(TaskScheduler.Default);