问题
A quick google search will tell you to avoid using async void myMethod()
methods when possible. And in many cases there are ways to make it possible. My question is basically an offshoot of this best practice:
What does the lambda expression below evaluate to?
Task.Run( async ()=> await Task.Delay(1000));
If it becomes an async Task
then we are following best practice.
But what if it evaluates to async void
?
回答1:
The documentation for expression lambdas says,
An expression lambda returns the result of the expression
So, for example, () => "hi"
returns a string, even though there is no return
statement. But if the expression doesn't return anything, like in () => Console.WriteLine("hi")
, then it's considered void
.
However there is a bit of trickery with async
lambdas. The expression await Task.Delay(1000)
doesn't really return anything in itself. However, the language can figure out that if you have an async
lambda, you likely want it to return a Task
. So it will prefer that.
So this:
Task.Run(async () => await Task.Delay(1000));
Is equivalent to this, if you were to express it with a named method:
private async Task Wait1000() {
await Task.Delay(1000);
}
Task.Run(Wait1000);
But it is important to note that async
lambdas can be inferred to be async void
. The only reason it is considered async Task
here is because Task.Run
has an overload for Func<Task>. If the only available overload took an Action parameter, then it would be inferred to be async void
, without any warning to you.
For example, this produces no error and the lambda is treated as async void
:
private void RunThisAction(Action action) {
action();
}
RunThisAction(async () => await Task.Delay(1000));
That is different than if you passed it a named async Task
method, which would cause a compiler error:
private void RunThisAction(Action action) {
action();
}
private async Task Wait1000() {
await Task.Delay(1000);
}
RunThisAction(Wait1000); // 'Task Wait1000()' has the wrong return type
So be careful where you use it. You can always hover over the method name (like the Run
in Task.Run
) and Visual Studio will tell you which overload it has inferred:
回答2:
Yeah, it is evaluated to async Task
because Task.Delay(n)
has return type of Task
. So it is good practice.
In addition, there is msdn example, but it is a little bit more verbose:
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);
}
}
So the above code could be shortened to:
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await Task.Delay(1000);
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
}
And now shortened code looks like your code.
来源:https://stackoverflow.com/questions/61827597/async-void-lambda-expressions