C# 当需要保留某个执行顺序时,运行一组异步任务

C# 当需要保留某个执行顺序时,运行一组异步任务,c#,.net,async-await,C#,.net,Async Await,我正在尝试异步化我的原始代码 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=newli

我正在尝试异步化我的原始代码

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=newlist();
for(项目中的var项目)
{ 
添加(dbAccess.SaveAsync(项));
}
等待任务。何时(任务);
但是,在将项目保存到数据库之前,我需要添加一个额外的清理调用:

   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);
var tasks=newlist();
for(项目中的var项目)
{ 
Add(dbAccess.deleteAncy(item.id));
添加(dbAccess.SaveAsync(项));
}
等待任务。何时(任务);
上述代码不正确,因为在完成相应的DeleteAsync之前,不应执行SaveAsync。换句话说,在保存每个项目之前,删除必须始终进行,但项目的顺序并不重要

有一种完美的方法可以做到这一点吗?

您可以使用
Func
将两个异步调用封装到一个
任务中,如下所示:

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());
}
for(项目中的变量项目)
{
//我们将item的值存储在局部变量中
//因为不建议关闭循环变量
var my_item=项目;
Func task_fact=async()=>
{
等待dbAccess.deleteAncy(my_item.id);
等待dbAccess.SaveAsync(我的_项);
};
添加(task_fact());
}
这将创建一个任务,该任务调用delete方法,异步等待它,然后调用save方法并异步等待它


您可以使用一种方法做同样的事情。

使用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);
var tasks=newlist();
for(项目中的var项目)
{ 
var task=dbAccess.deleteAncy(item.id)
.ContinueWith(先行项=>dbAccess.SaveAsync(项))
.Unwrap();
任务。添加(任务);
}
等待任务。何时(任务);

创建一个
async
方法,对单个项目执行删除,然后执行保存,并对每个项目并行执行所有这些复合操作:

var tasks = items.Select(async item => 
{
    await dbAccess.DeleteAsync(item.id);
    await dbAccess.SaveAsync(item);
});
await Task.WhenAll(tasks);

先发出所有删除,等待它们,然后发出所有保存,然后等待它们,怎么样?否则,您应该将每个删除+保存打包到一个任务中。很好,我简化了我的代码以解决这个问题。我不能执行你的建议,因为还有一点我没有表现出来。实际上DeleteAsync会返回需要传递给SaveAsync的其他内容。那么呢?将它们打包成一个任务,首先调用deleteasync,然后再调用saveasync?我不能。我必须向SaveAsync传递另一个参数,该参数只能从DeleteAsync获得。我给出了一个过于简化的示例,仅用于演示目的。这里涉及的更多。我只想在Method2Async之前严格调用Method1Async,而这两个方法可以在集合的每个元素上以随机顺序调用。是的,我理解这一点,但如果您在单个任务上首先调用DeleteAsync,并从中获取值,然后将其传递给SaveAsync,您应该能够做到这一点。坦率地说,我们只能提供与您发布的代码相关的答案。如果建议的解决方案符合您发布的代码,但不是真正的代码,那真的不是我们的问题。这是您的。您需要打开结果,因为当前您没有等待保存完成。它也比使用
await
要混乱得多,并且可能没有您想要的错误处理语义。