在异步方法中处理空任务的最佳方式是什么?

16

async 方法中如何处理 null 任务是最好的方式?

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;
   }
}

6
你想做什么? - i3arnon
1
我会这样写 public MyClass(Task task){if (task == null)throw new ArgumentNullException("task");..} - John Saunders
1
不要接受空任务。顺便问一下,你在尝试做什么?包装一个任务并添加一个执行方法非常可疑,可能是代码异味 - 试图“控制”任务何时开始或执行,而没有理由这样做。任务本身就是一个抽象类,用于描述其委托何时开始和执行,您不需要添加另一个类来完成相同的操作。 - Panagiotis Kanavos
1
我正在尝试理解在异步方法中处理可能为空的任务的最佳实践。为了讨论方便,假设我继承了一个可能允许空任务的方法,并且在构造函数中添加空检查不是一个选项。 - Robin
3个回答

26

您不需要处理null任务。只需对其进行空值检查:

public async Task Execute()
{
   if (task != null)
   {
       await task;
   }
}

或者更好的方法是,因为您在await之后没有添加任何内容,所以只需返回任务:

public Task Execute()
{
   return task;
}

如果你想返回一个已完成的任务而不是 null,你可以使用 Task.FromResult

public Task Execute()
{
   return task ?? Task.FromResult(false);
}

1
当您拥有一个无法严格抽象化的可重写方法时,“Task.FromResult(false)”非常有效。感谢您提供的出色答案。 - Xcalibur37
现在 Elvis 操作符(.?)非常常见 - 我有一个扩展方法,使用这种方法来确保那些 await 调用总是有效的:public static Task<T> NullSafe<T>(this Task<T> task) => task ?? Task.FromResult(default(T)); - 所以你可以编写像 var x = await (someObject?.DoTheThing()).NullSafe(); 这样的代码。(请记住,由于 Elvis 操作符的工作方式,此语句中的括号是重要的。) - BrainSlugs83
5
"Task.CompletedTask" 也是一种选项。 - Jesse Sierks

16
大多数异步代码如果任务从不为空,会更清晰易读。请使用Task.FromResult(0)或类似结构体代替空任务。
public class MyClass
{
  private readonly Task task;
  public MyClass(Task task) { this.task = task ?? Task.FromResult(0); }

  public async Task ExecuteAsync()
  {
    await task;
  }
}

或者,如果你的 ExecuteAsync 真的只做这些事情:

public Task ExecuteAsync()
{
  return task;
}

注意,当构造函数被调用时,该任务已经在运行,这使得方法名ExecuteAsync是一个误称。如果你想要任务在ExecuteAsync被调用时开始,则你真正想要存储的是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();
  }
}

0
什么是在异步方法中处理空任务的最佳方法?
最佳实践通常包括不允许空参数(除非业务规则要求)。
public class MyClass
{
   private readonly Task _task;

   public MyClass(Task task) 
   { 
     if (task == null)
     {
       throw new ArgumentNullException("task");
     }

     this._task = task; 
   }

   public async Task Execute()
   {
      await this._task;
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接