从基本方法返回任务

use*_*851 0 c# asynchronous async-await windows-runtime uwp

我仍在掌握异步编程的过程中,并且对如何修改以下内容有些困惑:

基本虚拟方法:

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

     await Task.Yield();
}
Run Code Online (Sandbox Code Playgroud)

覆盖方法:

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

     return base.OnSuspendingAsync(s, e);
}
Run Code Online (Sandbox Code Playgroud)

问题:

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

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!
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,应该对return base.OnSuspendingAsync(s, e);哪个 Visual Studio 正确标记为错误的更改(以及为什么)进行更改?

Pet*_*iho 5

你应该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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

您要确保Task在基方法Task本身指示完成之前,它不会指示完成。因此,在现在的异步方法中您需要做的最后一件事是await基本方法的结果。这样做时,您的方法直到发生这种情况后才有效地终止,因此它自己的Task对象(代表自己的工作)在基方法的完成之前不会指示完成。

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


附录:

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

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

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

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

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

    Usingawait是确保Task您的OnSuspendingAsync()覆盖返回的内容在基本实现本身完成之前不会指示完成。