【问题标题】:Where is the return statement in async/awaitasync/await 中的 return 语句在哪里
【发布时间】:2014-08-13 04:17:49
【问题描述】:

我可能已经使自己陷入了一种相当不成熟的困惑。请参考以下代码(控制台应用)

namespace Tasks101
{
    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            var x = p.Blah();                
        }

        private async Task Blah()
        {
            await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
        }

        private async void ReturnsVoid()
        {
            await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
        }

        private void Nothing()
        {

        }
    }
}

我的问题是,在 Blah() 方法中,当它执行时我还没有任何明确的 return 语句

var x = p.Blah();

x 的类型是Task。同样,ReturnsVoid 方法中没有返回语句,但也可以编译。

所以问题是

  1. 什么是从 Blah 方法返回 Task 而我没有 return 语句,为什么同样的事情没有从 ReturnsVoid 方法返回任何东西。
  2. 如何控制Blah 方法返回的内容?如果我有两个一个接一个的等待语句怎么办?

【问题讨论】:

  • 这是编译器的魔法。当您返回 Task 时,会包含整个方法,而不仅仅是一个语句。您应该将所有内容视为您等待的一个内聚块,并在内部等待其他块。

标签: c# .net task-parallel-library async-await


【解决方案1】:

async 关键字转换方法并构造返回的Task 实例。 async void 方法没有返回任何内容,因为它返回 void;缺少Task 是您应该避免使用async void 的原因之一。 async void 不是 自然 异步方法签名;仅支持它以便事件处理程序可能是async

如果你想返回一个,那么你应该让方法返回一个Task<T>,例如Task<int> BlahAsync(),然后你可以直接返回值,例如@987654335 @方法中awaits的个数与它无关。当方法执行实际返回时(例如,return 13),async 关键字将其解释为完成已经构造的Task<int>

我有一个async intro on my blog,您可能会觉得有帮助。

【讨论】:

  • 顺便说一句,是您的博客和您在 MSDN 杂志上的文章引导我走上了这条道路。最近我与 Tasks 合作过很多次,但这次我对语法的困惑比其他任何事情都多。那么我们是说“async”关键字修改了方法以在 Task 的情况下返回 Task a T 或在方法被声明为返回 void 时返回 void?如果是这样,那么它与 MSDN 文档完全矛盾,后者说 async 所做的唯一事情是在方法构造中启用 await 。想法?
  • async 关键字也会触发状态机转换,非常类似于用于枚举器块 (yield return) 的转换。
  • 明白了,谢谢。最后一个疑问。再次借鉴图 3 中 msdn.microsoft.com/en-us/magazine/dn630647.aspx 的示例,您有两个 await 语句。那么,当控制流在第一次和第二次等待时中断执行时,它将返回到调用方法的什么等待呢?一个代表第一个等待调用还是第二个?
  • async 方法返回的任务(等待)始终代表整个方法。所以在方法完成之前它不会完成,包括它的所有awaits。
  • 谢谢斯蒂芬。现在一切就绪。在相关主题上,我注意到我在上面提到的您的 MSDN 文章 (msdn.microsoft.com/en-us/magazine/dn630647.aspx) 中的源代码存在一些问题。我已将我的 cmets 留在您的文章中,说明问题是什么以及如何解决。我还写了一篇博客文章,解释了这里的固定源代码nikgupta.net/2014/08/async-mvvm-patterns 很想知道你对它的想法。
【解决方案2】:
  1. 编译器正在为您生成一个代表整个异步操作的Task
  2. 异步方法有 3 个选项:
    • async void - 在除事件处理程序之外的所有情况下都应避免这种情况
    • async Task - 这里你无法控制返回的任务,无论你有多少等待,它都会在整个操作结束(或抛出异常时)完成。
    • async Task<T> - 这允许实际返回一个值,但行为与 async Task 相同。

【讨论】:

    猜你喜欢
    • 2019-09-29
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 2017-02-03
    • 2021-06-04
    • 2019-01-03
    相关资源
    最近更新 更多