所以我在C#中学习了async / await,我制作了一个小型Windows窗体应用程序,只用async / await。我想出了这些:
以下两种方法使用button1_Click
:
private void button1_Click(object sender, EventArgs e)
{
GetSiteAsync();
}
以下是该应用的外观:
方法1:
public async void GetSiteAsync()
{
HttpClient ht = new HttpClient();
Task<string> getTaskString = ht.GetStringAsync("http://stackoverflow.com");
label1.Text = "Loading...";
string siteString = await getTaskString;
label1.Text = "Finished! Site Length = " + siteString.Length;
}
方法2:
public async void GetSiteAsync()
{
HttpClient ht = new HttpClient();
string siteString = await ht.GetStringAsync("http://stackoverflow.com");
label1.Text = "Loading...";
label1.Text = "Finished! Site Length = " + siteString.Length;
}
在第一种方法中,当我点击“加载网址&#39;按钮,它将标签更改为&#39;等待...&#39;加载完成后,将其更改为“完成!”#39;附加网站长度。
在第二种方法中,当我点击按钮时,它不会更改标签,当操作完成时,它会将标签更改为网站长度。
我注意到两种方法不导致程序GUI在加载网站时冻结。
那么为什么第二种方法无法将按钮更改为“正在加载...&#39; ??
”答案 0 :(得分:3)
在await
中的呼叫完成后执行await
运算符后的代码。这可以在另一个线程中完成。在后台创建了一个状态机,我们说await
之后的代码将继续执行。
所以在第一种情况下,
Task<string> getTaskString = ht.GetStringAsync("http://stackoverflow.com");
label1.Text = "Loading...";
您只需进行异步调用,然后设置Text
的{{1}}值。
在第二种情况下,
label1
你string siteString = await ht.GetStringAsync("http://stackoverflow.com");
label1.Text = "Loading...";
这个电话。这意味着在完成此异步调用后,将执行await
的setter。
答案 1 :(得分:2)
第二种方法会立即跳转到label1.Text = "Finished! Site Length = " + siteString.Length;
行之后的label1.Text = "Loading...";
行,因此您实际上从未看到它。第一种方法,你看,因为等待发生在之后。
所以: 第一种方法:&#34; loading&#34; - &GT;等待 - &gt; &#34;!成品&#34; 第二种方法:等待 - &gt; &#34;装载&#34; - &GT; &#34;成品&#34;!
&#34; loading&#34;立即用第二种方法写出来。
答案 2 :(得分:1)
在第一种方法中,您将标签测试设置为加载,然后await
任务。
在第二种方法中你await
任务(意味着你没有继续执行方法中的其余代码,直到它已经完成)和然后你将标签设置为加载(然后立即将其设置为完成)。
这些方法不会阻止UI线程,因为它们是异步的;它们很快将控制权返回给调用代码,并在产生控制权后继续工作。