Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to await for override async function?

We have a generic Job class which have an abstract HeavyTask method like this:

abstract class Job {
    private Task m_task; 
    protected abstract void HeavyTask(); 

    public void StartJob(){
        m_task = Task.Run(() => HeavyTask());
    }
    public async Task WaitJob(){
        await m_task; 
    }
}

And the derived class override the HeavyTask function and also make it async:

class JobFoo : Job {
    protected override async void HeavyTask()
    {
        await Task.Delay(1000);
        Debug.WriteLine("JobFoo is done");
    }
}

Then when we are using this method, it seems that the HeavyTask() is not awaited:

Job job = new JobFoo();
job.StartJob();
await job.WaitJob();
Debug.WriteLine("All Done");

Output:

All Done
JobFoo is Done

If we don't have async for the override HeavyTask, then it is working as expected. But I cannot guarantee those whose override the Job won't make the HeavyTask async. I want to understand why it is not awaited successfully and is there a way to make sure it will awaited? If you can, could you also explain whether it is a good practice to override a non-async function as async as shown above?

like image 568
Yuchen Avatar asked Feb 09 '23 21:02

Yuchen


1 Answers

It's not awaited because there's no awaitable (i.e. Task) to await. That method has a void return type. And you should avoid using async void outside of event handlers.

If you want to enable a derived class to use async have the method return a Task to begin with:

 protected abstract Task HeavyTaskAsync();

And if you then need to have a synchronous override return a Task synchronously:

override Task HeavyTaskAsync()
{
    // do stuff;
    return Task.CompletedTask;
}
like image 171
i3arnon Avatar answered Feb 11 '23 13:02

i3arnon