【问题标题】:What is wrong using Async and Await in this WPF example?在这个 WPF 示例中使用 Async 和 Await 有什么问题?
【发布时间】:2016-07-05 19:12:20
【问题描述】:

我是 await async 的新手,我想了解我在这个真实场景中对该主题的研究:

我有一个读取比特币价格的简单代码,需要 1-2 秒,我不想使用 await async 锁定 UI,并且在加载或完成时仍然给出状态:

    private void button_Click(object sender, RoutedEventArgs e)
    {
        Task<int> bitcoinPriceTask = GetBitcoinPrice();
        lblStatus.Content = "Loading...";
    }

    protected async Task<int> GetBitcoinPrice()
    {
        IPriceRetrieve bitcoin = new BitcoinPrice();
        string price = bitcoin.GetStringPrice();
        txtResult.Text = price;
        lblStatus.Content = "Done";
        return 1;
    }

根据要求,这里是 BitcoinPrice 类的实现:

public class BitcoinPrice : IPriceRetrieve
{
    public BitcoinPrice()
    {
        Url = "https://www.google.com/search?q=bitcoin%20price";
    }

    public string Url { get; }


    public string GetStringPrice()
    {
        var html = RetrieveContent();
        html = MetadataUtil.GetFromTags(html, "1 Bitcoin = ", " US dollars");
        return html;
    }

    public float GetPrice()
    {
        throw new NotImplementedException();
    }

    public string RetrieveContent()
    {
        var request = WebRequest.Create(Url);
        var response = request.GetResponse();
        var dataStream = response.GetResponseStream();
        var reader = new StreamReader(dataStream);
        var responseFromServer = reader.ReadToEnd();
        return responseFromServer;
    }
}

【问题讨论】:

  • 想一想,您的问题是“在这个 WPF 示例中使用 Async 和 Await 有什么问题?”请指出使用await的行。
  • WebRequest 有点重,您可以将所有RetrieveContent() 替换为public async Task&lt;string&gt; RetrieveContent() { using(var wc = new WebClient()) { return await wc.DownloadStringAsync(Url); } } 然后编辑GetStringPrice 以var html = await RetrieveContent(); 开头

标签: c# async-await


【解决方案1】:

你的代码现在有很多问题,首先你需要你的事件处理程序是async,这样你就可以在返回Task&lt;int&gt;的方法上等待,其次你可以在调用方法和等待之前设置消息加载以便它等待该方法完成它以及何时完成工作返回结果然后将消息设置为完成:

private async void button_Click(object sender, RoutedEventArgs e)
{
     lblStatus.Content = "Loading...";
     int bitcoinPriceTask = await GetBitcoinPrice();
     lblStatus.Content = "Done";

}

protected async Task<int> GetBitcoinPrice()
{
     IPriceRetrieve bitcoin = new BitcoinPrice();
     string price = await bitcoin.GetStringPrice();
     txtResult.Text = price;
     return 1;
}

或者更好的是可以返回 Task&lt;string&gt; 并在事件处理程序中设置 TextBox 值:

protected async Task<string> GetBitcoinPrice()
{
    IPriceRetrieve bitcoin = new BitcoinPrice();
    string price = await bitcoin.GetStringPrice();
    return price;
}

在事件处理程序中:

private async void button_Click(object sender, RoutedEventArgs e)
{
     lblStatus.Content = "Loading...";
     string price = await GetBitcoinPrice();
     txtResult.Text = price;
     lblStatus.Content = "Done";

}

【讨论】:

  • 在您的“更好的版本”中,您还可以在GetStringPrice() 上添加.ConfigureAwait(false),因为您不再在GetBitcoinPrice() 方法中触摸用户界面。
  • 谢谢,不确定我是否遗漏了什么,但它仍然会锁定用户界面
  • @ThePoet 您可能错过的是BitcoinPrice.GetStringPrice() 还需要返回Task&lt;string&gt;。整个方法链应该是异步的,直到您进行网络调用以查找价格。 (您也可以将其包装在 Task.Run( 中,但使调用链与网络调用异步是更好的选择)
  • @ThePoet GetBitcoinPrice()的实现是什么?
  • 您可以将 var response = request.GetResponse(); 替换为 var response = await request.GetResponseAsync();,然后使整个链的其余部分异步,根据需要等待。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
相关资源
最近更新 更多