Reputation:
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?
Upvotes: 2
Views: 603
Reputation: 244757
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()
).
Upvotes: 2
Reputation: 9407
It should look more like this:
public async Task LoadMusicAsync()
{
await Task.Run(() => this.LoadMusicInner());
}
private void LoadMusicInner()
{
// Work here..
}
Upvotes: 5