Reputation: 1902
I am trying to asynchronize my original code
for(var item in items)
{
dbAccess.Save(item);
}
which works fine:
var tasks = new List<Task>();
for(var item in items)
{
tasks.Add(dbAccess.SaveAsync(item));
}
await Task.WhenAll(tasks);
However, I need to add an additional clean-up call before I save and item to my DB:
var tasks = new List<Task>();
for(var item in items)
{
tasks.Add(dbAccess.DeleteAsync(item.id));
tasks.Add(dbAccess.SaveAsync(item));
}
await Task.WhenAll(tasks);
This code above is incorrect since SaveAsync should not be executed until the corresponding DeleteAsync is finished. In other words Deletion must always go before Saving for each item but the order for the items does not matter.
Is there a perfect way to do this ?
Upvotes: 9
Views: 9509
Reputation: 27861
You can use a Func<Task>
to encapsulate the two async calls into a single Task
like this:
for(var item in items)
{
//We store the value of item in a local variable
//because it is not recommended to close over a loop variable
var my_item = item;
Func<Task> task_fact = async () =>
{
await dbAccess.DeleteAsync(my_item.id);
await dbAccess.SaveAsync(my_item);
};
tasks.Add(task_fact());
}
This will create a Task that calls the delete method, asynchronously wait for it, and then calls the save method and asynchronously wait for it.
You can do the same thing using a method.
Upvotes: 3
Reputation: 62472
How about using ContinueWith:
var tasks = new List<Task>();
for(var item in items)
{
var task = dbAccess.DeleteAsync(item.id)
.ContinueWith(antecedent => dbAccess.SaveAsync(item))
.Unwrap();
tasks.Add(task);
}
await Task.WhenAll(tasks);
Upvotes: 2
Reputation: 203828
Create an async
method that performs the delete, then the save, for a single item, and perform all of those composite operations on each item in parallel:
var tasks = items.Select(async item =>
{
await dbAccess.DeleteAsync(item.id);
await dbAccess.SaveAsync(item);
});
await Task.WhenAll(tasks);
Upvotes: 9