完全被async / await困惑

时间:2013-12-12 16:01:05

标签: .net asynchronous async-await c#-5.0

好的,所以我正在开发一款小型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。这就是我感到困难的地方。我的方法开始是无效的,因为它确实没有返回任何东西。我该怎么办呢?

2 个答案:

答案 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}})。