3 回答
TA贡献1862条经验 获得超6个赞
考虑以下两条路径:
textBox1.Text += await task;
对比
string newText = await task;
textBox1.Text += newText;
在第一个示例中,textBox1.Text 的当前值首先被所有三次单击立即读取,这可能只是原始的空文本框值。然后,当每个完成时,它会写入原始值(就像读取时一样,提醒仍然是空字符串)加上您要连接的“1”。所以如果你快速点击按钮,三个线程都会写入“”+“1”的值
在第二个示例中,您等待获取要连接的结果文本,然后(在 UI 线程上)执行 += 操作,该操作将不间断地读取、连接和写入。
如果您在 += 中等待,则在开始等待之前读取原始值,并将结果连接应用于保存在等待上下文中的值。
现在这有意义吗?
TA贡献1827条经验 获得超7个赞
某些语言(例如 C++)允许编译器选择在给定语句中计算的顺序表达式。但是 C# 消除了这种歧义:评估总是从左到右。
textBox1.Text += await task;
在 C# 中,没有特殊的 += 运算符,它只是扩展为:
textBox1.Text = textBox1.Text + await task;
现在,如果我们从左到右评估,它应该评估的第一件事是 textBox1.set_Text 用于赋值。如果您要在右侧执行一些会更改 textBox1 的值的操作,您最终仍会分配给原始 textBox1,而不是新值。
接下来要评估的是 textBox1.get_Text。这应该返回您的“”值。
然后它评估“等待任务”。此时,它陷入等待,无法继续评估语句,因此它将当前堆栈帧的重要内容转储到堆对象中以备后用。当它回来继续评估时,我们现在评估了以下信息:
我们要写入的对象的地址。
字符串值“”。
字符串值“1”。
剩下要做的就是将捕获的“”添加到等待的“1”,并将其分配给捕获的 textBox1。
如果您快速连续多次执行此操作,则所有 3 个输入每次都将相同。换句话说,它的行为与标准所描述的完全一致。人们给出的建议将其放在上一行,如下所示:
var temp = await task; textBox1.Text += temp;
这只是将等待移到 textBox1.Text 之前。您实际上可以进行重新排序内联并给出预期的结果,只需颠倒语句中表达式的顺序即可:
textBox1.Text = string.Concat( new[] { await task, textBox1.Text }.Reverse());
TA贡献1856条经验 获得超11个赞
这里没有编译器错误。但是,这条线是你的问题
textBox1.Text += await task;
如果您更改以下内容,您会发现一致的结果。
var result = await task; textBox1.Text += result;
一个简单的类比是您向某人询问结果(例如单词或数字),当您完成自己的工作后,您希望将结果添加到他们的结果中。当您非常快地多次执行此操作时,就会出现问题。你得到了他们原来的价值 3 次(你说,给我你所拥有的,给我你所拥有的,给我你所拥有的),你要去做你的 3 个独立的工作,当你回来时你只需添加它到原始值(未修改的值),这似乎有效地覆盖了该值并且不起作用。
- 3 回答
- 0 关注
- 135 浏览
添加回答
举报