一个快速的谷歌搜索会告诉你尽可能避免使用async void myMethod()
方法。并且在许多情况下,有办法使之成为可能。我的问题基本上是这个最佳实践的一个分支:
下面的 lambda 表达式的计算结果是什么?
Task.Run( async ()=> await Task.Delay(1000));
如果它变成了,async Task
那么我们将遵循最佳实践。
但是,如果它评估为async void
怎么办?
表达式 lambda 返回表达式的结果
因此,例如,() => "hi"
返回一个字符串,即使没有return
语句。但是如果表达式没有返回任何东西,比如 in () => Console.WriteLine("hi")
,那么它被认为是void
。
async
然而, lambdas有一些技巧。表达式await Task.Delay(1000)
本身并没有真正返回任何东西。但是,该语言可以计算出,如果您有一个async
lambda,您可能希望它返回一个Task
. 所以它会更喜欢那个。
所以这:
Task.Run(async () => await Task.Delay(1000));
相当于这个,如果你用命名方法来表达它:
private async Task Wait1000() {
await Task.Delay(1000);
}
Task.Run(Wait1000);
但重要的是要注意async
lambda可以推断为async void
. 在这里考虑它的唯一原因async Task
是因为. 如果唯一可用的重载带有一个参数,那么它将被推断为,而不会向您发出任何警告。Task.Run
Func<Task>
Action
async void
例如,这不会产生错误,并且 lambda 被视为async void
:
private void RunThisAction(Action action) {
action();
}
RunThisAction(async () => await Task.Delay(1000));
这与将命名方法传递给它不同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
in Task.Run
),Visual Studio 会告诉您它推断出的重载:
是的,它被评估为async Task
因为Task.Delay(n)
返回类型为Task
. 所以这是一个很好的做法。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await ExampleMethodAsync();
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
private async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}
所以上面的代码可以缩短为:
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await Task.Delay(1000);
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
}
现在缩短的代码看起来像你的代码。