In the code below I need to execute the three Get... methods in parallel. When a Get... method completes I need to immediately call the Save... method. Note Save... takes thing as a parameter. All Get and Save methods must complete before DoStuffAsync returns.
My guess is that I need a continuation on the Get... methods but I dont know how to construct it.
protected async void DoStuffAsync()
{
SomeThing thing = new SomeThing { ID = 5 };
SomeRepository rep = new SomeRepository();
// We need to run all three Get... methods in parallel
// As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method .
var getRed = rep.GetRedAsync().ContinueWith<Task<string>>(async x => { thing.Color1 = x.Result; await rep.SaveRedAsync(thing); return x; }); // does not compile
var getBlue = rep.GetBlueAsync();
var getGreen = rep.GetGreenAsync();
string red = await getRed.Result; // this is not good because getBlue may finish before getRed. We want dont want to wait on getRed before calling SaveBlue
await rep.SaveRedAsync(thing);
var b = await getBlue;
var c = await getGreen;
// thing must be fully initialized before DoStuffAsync returns
}
public class SomeThing
{
public int ID { get; set; }
public string Color1 { get; set; }
public string Color2 { get; set; }
public string Color3 { get; set; }
}
public class SomeRepository
{
public async Task<string> GetRedAsync()
{
return await Task.Run(() => "red");
}
public async Task<string> GetBlueAsync()
{
return await Task.Run(() => "blue");
}
public async Task<string> GetGreenAsync()
{
return await Task.Run(() => "green");
}
public async Task SaveRedAsync(SomeThing thing)
{
// We need thing.ID here as well as other properties
await Task.Delay(1);
}
public async Task SaveBlueAsync(SomeThing thing)
{
await Task.Delay(1);
}
public async Task SaveGreenAsync(SomeThing thing)
{
await Task.Delay(1);
}
}
Well, you could explicitly use ContinueWith
- or you could break off each "get and save" into a separate async method or async lambda. For example:
async Task GetAndSaveRedAsync(SomeThing thing, SomeRepository rep)
{
var red = await rep.GetRedAsync();
thing.Red = red;
await SaveRedAsync(red);
// Return red if you want (change the return type to Task<string>)
}
// Ditto for the others
Then:
protected async void DoStuffAsync()
{
SomeThing thing = new SomeThing { ID = 5 };
SomeRepository rep = new SomeRepository();
var handleRed = GetAndSaveRedAsync(thing, rep);
var handleBlue = GetAndSaveBlueAsync(thing, rep);
var handleYellow = GetAndSaveYellowAsync(thing, rep);
// Or use Task.WhenAll
await handleRed;
await handleBlue;
await handleYellow;
}
I would not mix ContinueWith
and await
and rather use an async
lambda directly:
protected async Task DoStuffAsync()
{
SomeThing thing = new SomeThing { ID = 5 };
SomeRepository rep = new SomeRepository();
// We need to run all three Get... methods in parallel
// As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method .
Func<Task<X>> getRedFunc = async() =>
{
var result = await rep.GetRedAsync();
thing.Color1 = result;
await rep.SaveRedAsync(thing);
return result;
};
var getRed = getRedFunc();
var getBlue = rep.GetBlueAsync();
var getGreen = rep.GetGreenAsync();
await Task.WhenAll(getRed, getBlue, getGreen);
}
Also, don't use async void
methods for anything but event handlers. You won't be able to observe the completion of a method like this or handle exceptions possibly thrown inside it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With