Я пытаюсь синхронизировать исходный код

for(var item in items)
{
    dbAccess.Save(item);
}

Который отлично работает:

    var tasks = new List<Task>();

    for(var item in items) 
    { 
      tasks.Add(dbAccess.SaveAsync(item)); 
    }

    await Task.WhenAll(tasks);

Однако мне нужно добавить дополнительный вызов очистки, прежде чем я сохраню и добавлю в свою БД:

   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);

Этот код выше неверен, поскольку SaveAsync не должен выполняться до завершения соответствующего DeleteAsync. Другими словами, удаление всегда должно происходить перед сохранением для каждого элемента, но порядок элементов не имеет значения.

Есть ли лучший способ сделать это?

9
AstroSharp 25 Фев 2016 в 19:30

3 ответа

Лучший ответ

Создайте метод async, который выполняет удаление, а затем сохранение для одного элемента, и выполняет все эти составные операции с каждым элементом параллельно:

var tasks = items.Select(async item => 
{
    await dbAccess.DeleteAsync(item.id);
    await dbAccess.SaveAsync(item);
});
await Task.WhenAll(tasks);
6
Servy 25 Фев 2016 в 16:35

Вы можете использовать Func<Task> для инкапсуляции двух асинхронных вызовов в один Task следующим образом:

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());
}

Это создаст задачу, которая вызывает метод удаления, асинхронно ожидает его, а затем вызывает метод сохранения и асинхронно ожидает его.

Вы можете сделать то же самое, используя метод.

2
Yacoub Massad 25 Фев 2016 в 16:47

Как насчет использования 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);
1
Sean 25 Фев 2016 в 16:38