异步 void lambda 表达式

bwa*_*all 3 c# async-await generic-lambda

一个快速的谷歌搜索会告诉你尽可能避免使用async void myMethod()方法。在许多情况下,有办法使之成为可能。我的问题基本上是这个最佳实践的一个分支:

下面的 lambda 表达式的计算结果是什么?

Task.Run( async ()=> await Task.Delay(1000));
Run Code Online (Sandbox Code Playgroud)

如果它变成了,async Task那么我们将遵循最佳实践。

但是如果它评估为async void呢?

Gab*_*uci 5

表达式 lambdas的文档说,

表达式 lambda 返回表达式的结果

因此,例如,() => "hi"即使没有return语句也返回一个字符串。但是如果表达式没有返回任何东西,比如 in () => Console.WriteLine("hi"),那么它被认为是void

然而,asynclambdas有一些技巧。该表达式await Task.Delay(1000)本身并没有真正返回任何内容。但是,该语言可以确定,如果您有一个asynclambda,您可能希望它返回一个Task. 所以它会更喜欢那个。

所以这:

Task.Run(async () => await Task.Delay(1000));
Run Code Online (Sandbox Code Playgroud)

等价于这个,如果你用一个命名方法来表达它:

private async Task Wait1000() {
    await Task.Delay(1000);
}
Task.Run(Wait1000);
Run Code Online (Sandbox Code Playgroud)

但需要注意的是,可以asynclambda推断为. 它被认为是唯一的原因,在这里是因为有过载。如果唯一可用的重载带有一个参数,那么它会被推断为,而不会向您发出任何警告。async voidasync TaskTask.Run Func<Task>Actionasync void

例如,这不会产生错误,并且 lambda 被视为async void

private void RunThisAction(Action action) {
    action();
}
RunThisAction(async () => await Task.Delay(1000));
Run Code Online (Sandbox Code Playgroud)

这与将命名async Task方法传递给它的情况不同,后者会导致编译器错误:

private void RunThisAction(Action action) {
    action();
}
private async Task Wait1000() {
    await Task.Delay(1000);
}
RunThisAction(Wait1000); // 'Task Wait1000()' has the wrong return type
Run Code Online (Sandbox Code Playgroud)

所以在你使用它的地方要小心。您始终可以将鼠标悬停在方法名称上(例如Runin Task.Run),Visual Studio 会告诉您它推断出的重载:

在此处输入图片说明