我有两组任务,每组都有不同的结果类型:
IEnumerable<Task<T1>> set1 = GetTasksOfT1();
IEnumerable<Task<T2>> set2 = GetTasksOfT2();
现在我想在一行中等待两个集合,但我必须使用强制转换来设置set1:
await Task.WhenAll(set1.Select(p => p as Task).Concat(set2));
那是因为如果我不使用演员,我会收到此错误:
IEnumerable<Task<T1>>' does not contain a definition for 'Concat'
and the best extension method overload 'Queryable.Concat<Task<T2>>(IQueryable<Task<T2>>, IEnumerable<Task<T2>>)'
requires a receiver of type 'IQueryable<Task<T2>>'
这是显而易见的。
那么有没有一种方法可以使用单个WhenAll()而无需强制转换?
编辑: 返回类型T1和T2 非常重要 - 我等待任务后消耗它们:
//After await Task.WhenAll(...):
var t1Results = await set1; // all set1 Tasks are completed by now
var t2Results = await set2; // same
DoSomethingWithResults(t1Results, t2Results);
答案 0 :(得分:2)
实际上,编译器只是抱怨类型推断失败。你可以用它来帮助它:
IEnumerable<Task<int>> set1 = null;
IEnumerable<Task<string>> set2 = null;
set1.Concat((IEnumerable<Task>)set2); //#1
((IEnumerable<Task>)set1).Concat(set2); //#2
set1.Concat<Task>(set2); //#3
还有许多其他方法可以提供类型信息。这是有效的,因为IEnumerable
是协变的。这将调用Enumerable.Concat<Task>(IEnumerable<Task>, IEnumerable<Task>)
。
答案 1 :(得分:1)
如果GetTasksOfT1
和GetTasksOfT2
这两种方法都不会返回Task<T>
而Task
,那么您就不会有任何问题。
所以我建议重构这些方法来返回一系列Task对象,IEnumerable<Task>
或者拾取Kote的解决方案。
答案 2 :(得分:0)
如果您需要两组Task
的结果,那么不等待所有列表可能会更简单。
我想你的代码(使用usr&#39的建议)看起来像这样:
IEnumerable<Task<T1>> set1 = GetTasksOfT1();
IEnumerable<Task<T2>> set2 = GetTasksOfT2();
await Task.WhenAll(set1.Concat<Task>(set2));
var t1Results = await Task.WhenAll(set1);
var t2Results = await Task.WhenAll(set2);
在这里,合并的await
并没有真正起到任何作用。如果删除它,两个结果变量仍然会被正确初始化,因为它们有自己的await
。
答案 3 :(得分:0)
虽然如果创建一个数组比连接两个枚举更有争议,你可以将连接保留在等式之外:
await Task.WhenAll(set1, set2);
但是,既然你需要的是评估每个任务序列的结果,我就不用费心去等待它们了:
DoSomethingWithResults(await set1, await set2);