有人可以告诉我以下两种方法之间的区别,以及为什么会有不同的结果吗?我本以为方法2只是方法1的分解版本。我显然错过了一些关键的区别细节。什么事?
public interface IStrategy
{
Task<List<Result>> ExecuteAsync();
}
public async Task Execute(List<Result> results, IEnumerable<IStrategy> strategies)
{
// Approach 1, strategy will return 1 result, results collection will be empty at method exit
strategies.ForEach(async strategy => results.AddRange(await strategy.ExecuteAsync()));
// Approach 2, strategy will return 1 result, results collection will have one result at method exit
foreach (var strategy in strategies)
{
results.AddRange(await strategy.ExecuteAsync());
}
}
答案 0 :(得分:3)
List<T>.Foreach()
需要一个Action<T>
。您尝试传递给ForEach
的lambda由编译器转换为状态机,而在您await
内部strategy.ExecuteAsync()
调用时,该调用立即返回。
因此ForEach
认为尽管您的lambda实际上仍在等待strategy.ExecuteAsync()
,但它已经完成。 ForEach
无法(或指定)到await
该方法(委托人甚至无法将Task
返回到await
)。
因此,它迭代到下一个strategy
,而无需等待上一个ExecuteAsync()
。最终ForEach
返回,您不知道所有(或任何一个)策略是否已完全执行,它们可能仍在运行。
如果您在第一种方法返回后要等待一会儿,则results
列表应正确填写(但是,这当然不是您应该这样做的方式!第二种方法是正确的方法。)
第二种方法有效,因为您总是await
ExecuteAsync()
,然后才继续进行迭代。因此,在foreach
循环之后,所有策略都已执行。