Async void lambda expressions

吃可爱长大的小学妹 提交于 2021-01-24 08:06:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!