【问题标题】:"await" doesn't wait for the completion of call"await" 不等待调用完成
【发布时间】:2012-08-27 11:44:00
【问题描述】:

我正在构建一个 Metro 应用程序。

在 MainPage.xaml.cs 中,我将 Album 实例化如下:

Album album = new Album(2012);  //With the album ID as its parameter.
ListView1.ItemsSource = album.Songs;

在Album.cs中,构造函数如下:

public Album(int ID)
{
    this.ID = ID;
    Initialize();  //Serves as a wrapper because I have to call httpClient.GetStreamAsync() and "async" doesn't work for the constructor.
}

最后是 Initialize 方法:

private async void Initialize()
{
    //...some code...
    HttpClient cli = new HttpClient();
    Stream SourceStream = await HttpClient.GetStreamAsync("http://contoso.com");
    //...some code...
    this.Songs = Parse(SourceStream);
}

问题是当它运行到 GetStreamAsync 时,它会直接转到 ListView1.ItemsSource = album.Songs,并且专辑.Songs 为空。

这个问题有什么快速的解决方法吗?

【问题讨论】:

  • await 不能这样工作。它开始一个异步操作。您需要 await 获取代码中的结果。
  • @Vlad:不,await 本身不会启动异步操作。 await 只需将控制权交还并安排继续(当然,如果需要)。
  • @Jon:你说得对,它把控制权交还给我,我应该提到它,但是“安排一个延续”实际上与“启动一个异步操作”不一样吗?
  • @Vlad:不,它会安排它。在您等待的任何操作完成之前,该操作不会开始
  • @Vlad:不,因为GetStreamAsync 是启动操作的原因。这可能在await 表达式之前很长一段时间内发生——在基于异步任务的模式中,任务是“热的”,与 F# 不同。 await 表达式 only 在必要时安排延续 - 它不会启动操作。

标签: c# asynchronous .net-4.5


【解决方案1】:

是的。 asyncawait 的全部意义在于您不要阻止。相反,如果您正在“等待”一个尚未完成的操作,则会安排一个延续来执行异步方法的其余部分,并将控制权返回给调用者。

现在,因为您的方法的类型为 void,所以您甚至无法知道何时完成 - 如果您返回 Task(不需要对方法的主体进行任何更改),您将至少可以在它完成后解决。

不清楚您的代码是什么样的,但基本上您应该只在初始化完成后尝试设置ItemsSource。您可能也应该在异步方法中使用您的 MainPage 代码,这看起来像:

Album album = new Album(2012);
ListView1.ItemsSource = await album.GetSongsAsync();

您的GetSongs() 电话将是:

private async Task<List<Song>> GetSongsAsync()
{
    //...some code...
    HttpClient cli = new HttpClient();
    Stream SourceStream = await HttpClient.GetStreamAsync("http://contoso.com");
    //...some code...
    return Parse(SourceStream);
}

这意味着Songs 将不再是Album 本身的属性,尽管您可以根据需要添加它以进行缓存。

【讨论】:

  • 感谢您的详细解答!问题解决了。但更进一步,是否有任何替代 httpClient.GetStringAsync() 方法的方法?我的意思是过去的 webClient.DownloadString() 之类的东西。我不得不说,当不需要像 DownloadStringAsync() 这样的东西时,它在某些情况下真的很方便。
  • @IsilmëOrphousV:据我所知,它仍然在“正常”的 .NET 4.5 中——但不是在 WinRT 中……正是因为你应该以异步方式做事。跨度>
  • 真的应该叫它别的名字,beginAsync 也许吧。
【解决方案2】:

使Songs 属性返回Task&lt;List&lt;Song&gt;&gt; 并在ListView1.ItemsSource = await album.Songs; 等待

【讨论】:

  • 但是有没有任何绑定友好的方式来完成这个?
  • @IsilmëOrphousV binding-friendly way 是什么意思?
  • @L-B 它适用于 List 因为我只想将它用于 ItemsSource。但是如果我想绑定一首歌曲,它有一个属性表明它已经播放了多少次,一个通过异步调用远程检索的数字,将属性(Task)绑定到视图会很不方便。无论如何,我认为将它们全部包装到一个单独的方法中可能是一种解决方法,代码更多但另一方面更清晰。
  • 这意味着我也必须调用函数async。是不是可以只做包含HttpClient调用async的函数?
猜你喜欢
  • 2021-01-26
  • 2018-09-23
  • 2019-11-19
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多