Question

OK so I'm working on a little MP3 player app. It uses a DataSet to hold MP3 file info. This question is about how to load my DataSet asynchronously. I have been reading around quite a bit, and tried a bunch of stuff, but I just don't get it. All I want to do is take a long-running process DataSet fill process and make it asynchronous.

In The Beginning, I had a method of my DataSet (LoadMusic) that looked like this:

public partial class dsMusicPlayer
{
    public void LoadMusic()
    { ... }
}

It scans the MP3 files in a directory structure and fills the DataSet with the file info (title, artist, album, etc). It works, but takes a minute or so to run, and blocks the UI naturally. So, perfect candidate for being made asynchronous. I re-wrote my load method like this (without changing implementation otherwise):

public async void LoadMusicAsync()
{
}

I knew it wouldn't be that simple, but I'm going one step at a time. Sure enough, I get a warning that my async method 'lacks await operators.' All the reading I've done shows "await" being used before a method call, so I refactor the body of my original method out to a dummy private method whose only purpose is to allow the 'await' keyword to be used in the container/public method:

public async void LoadMusicAsync()
{
    await LoadMusicInner();
}

private void LoadMusicInner()
{
}

Next I see that I can't 'await void.' Fine. I change my private method to

private Task LoadMusicInner()
{
}

But now I get the error 'not all code paths return a value' -- it makes sense because the return type is Task. And here's the point where I feel stuck. My method was void to begin with because it really doesn't return anything. How should I have done this?

Was it helpful?

Solution

It should look more like this:

public async Task LoadMusicAsync()
{
    await Task.Run(() => this.LoadMusicInner());
}

private void LoadMusicInner()
{
    // Work here..
}

OTHER TIPS

If all you want to do is to execute some synchronous code on a background thread, then in your calling code, you can do something like:

await Task.Run(() => player.LoadMusic());

This requires you to make the whole method where you're making this call async. If it's not a top-level event handler, then it should be an async Task method and its caller should await it too, spreading async all the way to the top. The top-level event handler then should be async void (avoid async void pretty much everywhere else).

If you want to make your code truly asynchronous (i.e. not blocking a thread when doing IO), then you need to actually change the implementation of LoadMusic() by replacing synchronous calls (like reader.ReadLine()) into their asynchronous versions (like await reader.ReadLineAsync()).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top