【问题标题】:Returning a Task from a base method从基本方法返回任务
【发布时间】:2016-03-06 19:33:36
【问题描述】:

我仍在处理异步编程,对如何修改以下内容有点困惑:

基本虚方法:

public virtual async Task OnSuspendingAsync(object s, SuspendingEventArgs e)
{
     // do some housekeeping actions upon suspending in the base class

     await Task.Yield();
}

覆盖方法:

public override Task OnSuspendingAsync(object s, SuspendingEventArgs e)
{
     // do some housekeeping actions on exiting/suspending

     return base.OnSuspendingAsync(s, e);
}

问题:

现在,如果我在重写方法中使用 awaitable(几乎不可避免),我需要通过添加 async 关键字将 public override Task 更改为 public override async Task,如下面的真实示例所示。

public override async Task OnSuspendingAsync(object s, SuspendingEventArgs e)
{
   try
   {
     // tidy up app temporary folder on exit
     await ApplicationData.Current.ClearAsync(ApplicationDataLocality.Temporary);
   }
   catch { }

   return base.OnSuspendingAsync(s, e); // this is wrong with awaitable!
}

在这种情况下,return base.OnSuspendingAsync(s, e); 应该是什么(以及为什么)Visual Studio 正确地将其标记为错误?

【问题讨论】:

  • 你不只是等待基本方法吗?
  • 已经尝试过 return await base.OnSuspendingAsync(s, e); 并认为它必须更多,因为 Visual Studio 仍然标记错误。这让我很困惑。
  • 不,只需将return 替换为await
  • 在您的第一个覆盖示例中,您将返回由base.OnSuspendingAsync() 生成的Task。除了将它传递给重写方法的调用者之外,您没有做任何事情。在您的第二个覆盖示例中,您的方法通过异步生成 new Task。您的 Task 不返回任何内容,因此您的 return 语句是错误的。你只是想await你的基本任务。
  • 这样想...如果您将方法声明为async Task 而不是async Task<T>...它很像void 方法。它不直接返回任何类型的result。只需 Task 正在工作。

标签: c# asynchronous windows-runtime async-await uwp


【解决方案1】:

你应该await结果:

public override async Task OnSuspendingAsync(object s, SuspendingEventArgs e)
{
   try
   {
     // tidy up app temporary folder on exit
     await ApplicationData.Current.ClearAsync(ApplicationDataLocality.Temporary);
   }
   catch { }

   await base.OnSuspendingAsync(s, e);
}

在方法中有await 之前,该方法可以同步运行。您可以执行同步逻辑,然后调用异步基方法并将返回的 Task 对象作为您自己的返回值传递它用于跟踪其进度。

但是一旦你将await 引入你的方法,现在你自己的方法是异步的。它将在第一个await 返回,返回给调用者的Task 代表您的方法将执行的整个工作序列。

您要确保在基本方法的Task 本身指示完成之前,Task 不会指示完成。因此,您需要在现在的异步方法中做的最后一件事是 await 基本方法的结果。这样做时,您的方法实际上不会在此之后终止,因此它自己的 Task 对象(代表它自己的工作)在基方法执行之前不会指示完成。

请注意,这不是解决您的方案的唯一可能方法。但恕我直言,它是最易读且易于实现的。


附录:

我认为以上内容足以解释为什么使用await,但也许不是。详述上述内容,特别是回答“为什么returnawait代替?”的问题:

  1. 了解return 语句并未字面上 被替换,这一点很重要。在某些情况下,return await 是正确的。 IE。当async 方法实际上返回一个值并且该值是由一些等待操作产生时。

  2. 那么return 声明去了哪里?好吧:当你创建一个async 方法时,返回类型会改变。方法的返回类型必须是voidTaskTask<T>(其中T 当然是一些实际类型或定义的类型,而不是由return 语句返回的实际值参数)。

    这里我们必须使用Task,因为这是我们必须遵守的方法签名。但请注意,当没有返回实际值时,我们使用Task(即,否则该方法将是void)。所以我们的async 方法不能返回任何东西。你可以写return;,但不能写return <some value>;。我选择完全省略返回,但如果你更喜欢它,你可以添加return第二个await...

  3. 为什么添加了await。根据我上面的解释,我希望这更清楚。这就是导致该方法的执行在base.OnSuspendingAsync() 方法正在执行它的工作(异步)时被暂时挂起的原因。它与async 一起工作,向编译器指示方法中的一个点何时可以返回,然后在哪里继续执行。

    使用await 可以确保您的@ 返回的Task 987654358@ 覆盖并不表示在基本实现本身完成之前完成。

【讨论】:

    猜你喜欢
    • 2012-06-02
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多