What is the best way to handle a null
task inside an async
method?
public class MyClass
{
private readonly Task task;
public MyClass(Task task) { this.task = task; }
public async Task Execute()
{
if (task == null)
{
await Task.Yield(); /* Is this the best way? */
return;
}
await task;
}
}
in an async function that returns a Task or Task<T> , you simply return or return a value, and the result of the function is implicitly converted to a task, so there is no danger of returning null .
The addition of async/await to the C# language specification made it easier to write asynchronous code. However while writing code, you'll end up in some cases where you don't have a Task to return in a certain path of your logic or you have a virtual empty method.
Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns. This problem can crop up in many unexpected ways.
Async code can be used for both I/O-bound and CPU-bound code, but differently for each scenario. Async code uses Task<T> and Task , which are constructs used to model work being done in the background. The async keyword turns a method into an async method, which allows you to use the await keyword in its body.
You don't need to handle null
tasks. Simply null check it:
public async Task Execute()
{
if (task != null)
{
await task;
}
}
Or even better, simply return the task since you're not adding anything after the await
:
public Task Execute()
{
return task;
}
If you want to return a completed task instead of null
you can use Task.FromResult
:
public Task Execute()
{
return task ?? Task.FromResult(false);
}
Most asynchronous code is cleaner if tasks are never null. Instead of a null task, use Task.FromResult(0)
or some such construct.
public class MyClass
{
private readonly Task task;
public MyClass(Task task) { this.task = task ?? Task.FromResult(0); }
public async Task ExecuteAsync()
{
await task;
}
}
Or, if that's really all your ExecuteAsync
is doing:
public Task ExecuteAsync()
{
return task;
}
Note that the task is already running when the constructor is called, which makes the method name ExecuteAsync
a misnomer. If you want the task to start when ExecuteAsync
is called, then what you really want to store is a Func<Task>
:
public class MyClass
{
private readonly Func<Task> func;
public MyClass(Func<Task> func) { this.func = func ?? () => Task.FromResult(0); }
public async Task ExecuteAsync()
{
await func();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With