Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Task.WhenAll() for multiple Lists of different return types?

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);
like image 291
shay__ Avatar asked Jan 24 '16 08:01

shay__


People also ask

Whenall returns an array of the tasks awaiting?

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 at the same time?

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.

What is a tasks collection?

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.

Should I wait for all the list of task s?

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.


2 Answers

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

like image 50
usr Avatar answered Nov 14 '22 22:11

usr


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.

like image 29
Christos Avatar answered Nov 15 '22 00:11

Christos