2016-01-24 91 views
4

我有兩套任務的,每一個不同的結果類型:如何將Task.WhenAll()用於不同返回類型的多個列表?

IEnumerable<Task<T1>> set1 = GetTasksOfT1(); 
IEnumerable<Task<T2>> set2 = GetTasksOfT2(); 

現在我想在一行中等待兩集,但我不得不項目設置1採用鑄造:

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

'T1'和'T2'都堅持一個共同的接口嗎? –

+0

@YuvalItzchakov號 –

+0

@ Clockwork-Muse請參閱我的編輯。但是,使用阻塞方法'Task.WaitAll()'是一個很糟糕的建議。 –

回答

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

+0

很好的回答!我會去#3 :) –

1

如果這兩種方法,GetTasksOfT1GetTasksOfT2不會返回Task<T>Task,你沒有任何問題。

所以我建議重構這些方法來返回任務對象序列,IEnumerable<Task>或拾取Kote的解決方案。

+0

不,我需要在任務完成後使用這些結果。 –

0

如果您需要兩套Task s的結果,那麼不用等待所有列表可能會更簡單。

我想象你的代碼(使用USR的建議)是這樣的:

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

0

雖然是值得商榷的,如果創建一個數組比連接兩個可枚舉更好,你可以離開串聯的方程:

await Task.WhenAll(set1, set2); 

但是,因爲你所需要的是每個序列的評估結果我不打擾等待他們所有的作爲一個單一的集合:

DoSomethingWithResults(await set1, await set2);