Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to handle null task inside async method? [closed]

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;
   }
}
like image 650
Robin Avatar asked Dec 18 '14 16:12

Robin


People also ask

Can async method return null?

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 .

Can you await 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.

Why you shouldn't use async void?

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.

Can we use async without task?

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.


2 Answers

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);
}
like image 122
i3arnon Avatar answered Sep 19 '22 17:09

i3arnon


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();
  }
}
like image 27
Stephen Cleary Avatar answered Sep 23 '22 17:09

Stephen Cleary