"await/async":为什么2段代码运行不一样?

smw*_*dia 3 c# asynchronous task-parallel-library async-await c#-5.0

这是一个简单的WinForm应用程序来试验await/async关键字.下面是按钮的事件处理程序.

我快速单击按钮两次,间隔小于3000ms,因此后台线程尚未完成.

    private Task<String> f()
    {
        return Task.Run<String>(() =>
            {
                Thread.Sleep(3000);
                return Thread.CurrentThread.ManagedThreadId.ToString();
            }
        );
    }

    private async void async_btn_Click(object sender, EventArgs e)
    {
        Task<String> wait_task = f();

        //Code 1, this outputs first 3, and then 3 is REPLACED with 4.
        //this.async_lbl.Text += await wait_task;  //3 -> 4

        //Code 2, this outputs first 3, and then 34.
        //String wait_value = await wait_task;
        //this.async_lbl.Text += wait_value;  //3 -> 34
    }
Run Code Online (Sandbox Code Playgroud)

为什么1和2的输出不同?

谢谢!

以下是反映的代码:

3 - > 34

// WindowsFormsApplication1.Form1
private async void async_btn_Click(object sender, EventArgs e)
{
    Task<string> task = this.f();
    string str = await task;
    Label expr_AA = this.async_lbl;
    expr_AA.Text += str;
}
Run Code Online (Sandbox Code Playgroud)

3 - > 4

// WindowsFormsApplication1.Form1
private async void async_btn_Click(object sender, EventArgs e)
{
    Task<string> task = this.f();
    Label label = this.async_lbl;
    label.Text += await task;
}
Run Code Online (Sandbox Code Playgroud)

Ray*_*hen 11

这在C#语言规范中有解释.第14.3.2节:复合赋值:

[T]操作被评估为x = x op y,除了x仅被评估一次.

这条线

this.async_lbl.Text += await wait_task;
Run Code Online (Sandbox Code Playgroud)

扩展到

this.async_lbl.Text = this.async_lbl.Text + await wait_task;
Run Code Online (Sandbox Code Playgroud)

在执行该行时,this.async_lbl.Text是空字符串.因此,右侧评估为

"" + await wait_task
Run Code Online (Sandbox Code Playgroud)

然后代码等待任务的结果,并返回4.因此表达式的结果

"" + "4"
Run Code Online (Sandbox Code Playgroud)

是的"4".然后将其指定为文本this.async_lbl.请注意,在发生之前this.async_lbl.Text使用起始值.await

另一方面,

string wait_value = await wait_task;
this.async_lbl.Text += wait_value;
Run Code Online (Sandbox Code Playgroud)

扩展到

string wait_value = await wait_task;
this.async_lbl.Text = this.async_lbl.Text + wait_value;
Run Code Online (Sandbox Code Playgroud)

这一次,代码等待wait_task返回"4".但与此同时,价值this.async_lbl.Text变为"3".然后行

this.async_lbl.Text = this.async_lbl.Text + wait_value;
Run Code Online (Sandbox Code Playgroud)

执行,现在是右侧

"3" + "4"
Run Code Online (Sandbox Code Playgroud)

评估为"34".

  • 无论当前的设计是否"好",事实仍然是它是当前的语言设计,所以无论如何你都必须处理它. (3认同)