好的,所以我正在开发一款小型MP3播放器应用。它使用DataSet来保存MP3文件信息。这个问题是关于如何异步加载我的DataSet。我一直在阅读相当多的东西,并尝试了一些东西,但我只是不明白。我想做的就是采用长时间运行的DataSet填充过程并使其异步。
在The Beginning中,我有一个我的DataSet(LoadMusic)方法,如下所示:
public partial class dsMusicPlayer
{
public void LoadMusic()
{ ... }
}
它扫描目录结构中的MP3文件,并使用文件信息(标题,艺术家,专辑等)填充DataSet。它可以运行,但需要一分钟左右才能运行,并自然地阻止UI。因此,成为异步的完美候选者。我重写了这样的加载方法(不改变实现):
public async void LoadMusicAsync()
{
}
我知道这不会那么简单,但我一步一步走。果然,我得到一个警告,我的异步方法'缺乏等待运营商'。我所做的所有阅读都显示在方法调用之前使用“await”,所以我将原始方法的主体重构为一个虚拟私有方法,其唯一目的是允许在容器中使用'await'关键字/ public method:
public async void LoadMusicAsync()
{
await LoadMusicInner();
}
private void LoadMusicInner()
{
}
接下来我看到我不能'等待无效'。精细。我将我的私有方法更改为
private Task LoadMusicInner()
{
}
但现在我得到错误'并非所有代码路径都返回一个值' - 这是有道理的,因为返回类型是Task。这就是我感到困难的地方。我的方法开始是无效的,因为它确实没有返回任何东西。我该怎么办呢?
答案 0 :(得分:6)
看起来应该更像这样:
public async Task LoadMusicAsync()
{
await Task.Run(() => this.LoadMusicInner());
}
private void LoadMusicInner()
{
// Work here..
}
答案 1 :(得分:3)
如果您只想在后台线程上执行某些同步代码,那么在您的调用代码中,您可以执行以下操作:
await Task.Run(() => player.LoadMusic());
这要求您在进行此调用async
的地方制作整个方法。如果它不是顶级事件处理程序,那么它应该是async Task
方法,其调用方也应该await
,将async
一直传播到顶部。然后,顶级事件处理程序应为async void
(在其他任何地方都避免使用async void
。)
如果您想使您的代码真正异步(即在执行IO时不阻塞线程),那么您需要通过将同步调用(如LoadMusic()
)替换为reader.ReadLine()
来实际更改await reader.ReadLineAsync()
的实现。他们的异步版本(如{{1}})。