I have two sets of Tasks, each with different result type:
IEnumerable<Task<T1>> set1 = GetTasksOfT1();
IEnumerable<Task<T2>> set2 = GetTasksOfT2();
Now I would like to await both sets in one line, but I had to project set1 with cast:
await Task.WhenAll(set1.Select(p => p as Task).Concat(set2));
That's because I get this error if I don't use casting:
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>>'
Which is obvious.
So is there a way to use a single WhenAll() without casting?
Edit: The return types T1 and T2 are important - I consume them after the tasks are awaited:
//After await Task.WhenAll(...):
var t1Results = await set1; // all set1 Tasks are completed by now
var t2Results = await set2; // same
DoSomethingWithResults(t1Results, t2Results);
If the tasks you're awaiting have a result of the same type Task.WhenAll returns an array of them. For example for this class: public class Test { public async Task<TestResult> TestAsync () { await Task.Delay (1000); // Imagine an I/O operation. return new TestResult (); } }
How to Execute Multiple Tasks in C#? So far, we have been executing one task at a time, but sometimes we will have many tasks that we want to execute simultaneously. We can do that with Task.WhenAll method. With Task.WhenAll we can have a list of tasks and all the tasks will be executed concurrently.
A task that represents the completion of all of the supplied tasks. The tasks argument was null. The tasks collection contained a null task. The following example creates a set of tasks that ping the URLs in an array.
If you need the results of both sets of Task s, then it might be simpler to not wait for the all the lists. Bu here, the combined await doesn't really serve any purpose. If you remove it, both result variables will still be initialized correctly, because they have their own await s. Show activity on this post.
Actually, the compiler just complains about type inference failure. You can help it with that:
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
There are many other ways to provide the type information. This works because IEnumerable
is covariant. This will call Enumerable.Concat<Task>(IEnumerable<Task>, IEnumerable<Task>)
.
If both methods, GetTasksOfT1
and GetTasksOfT2
wouldn't return Task<T>
but Task
, you woulnd't have any problem.
So I suggest either refactor these method to return a sequence of Task objects, IEnumerable<Task>
or pickup the Kote's solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With