2

I am getting a compiler error for the following line of code:

IEnumerable<IPurchasedItem<IFruit>>[] result = await Task.WhenAll(
                repository1.LoadItems(id),
                repository2.LoadItems(id)
                );

Error CS0029 Cannot implicitly convert type 'void' to System.Collections.Generic.IEnumerable<IPurchasedItem<IFruit>>[]

My repository methods look like:

public async Task<IEnumerable<IPurchasedItem<Apple>>> LoadItems(int id) {}
public async Task<IEnumerable<IPurchasedItem<Orange>>> LoadItems(int id) {}

...where Apple and Orange descend from:

public interface IPurchasedItem<out T> : where T : IFruit {}
public class Fruit : IFruit {}
public class Apple : Fruit {}
public class Orange : Fruit {}

I've looked at this question, but it seems like I'm already doing what's suggested, i.e. asking for IEnumerable[] rather than Task<IEnumerable>[].

What am I doing wrong - and if this isn't the right approach then what is the best way for me to await and combine the results of both LoadItems() methods? I was originally planning on doing:

result[0].Concat(result[1])
Geoff
  • 8,551
  • 1
  • 43
  • 50

1 Answers1

5

Task<T> is a class, and therefore invariant. So a Task<string> is not a Task<object> - and as a more complicated example, a Task<IEnumerable<IPurchasedItem<Apple>>> is not a Task<IEnumerable<IPurchasedItem<Fruit>>> which is what you want it to be.

You could write a method to convert from one to another, of course - something like:

public static Task<TTarget> Convert<TSource, TTarget>(Task<TSource> task)
    where TSource : TTarget
{
    return await task;
}

Then you could convert all your specific tasks to Task<IEnumerable<IPurchasedItem<Fruit>>> tasks instead, and then Task.WhenAll will do what you want.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks Jon. I updated my question slightly to ask what the correct approach is, since this seems to be a dead end. – Geoff Jun 06 '16 at 20:04
  • 3
    @Geoff: I've already told you want the correct approach is - transform your individual tasks into a common task type before calling `Task.WhenAll`. So you'd call `Convert(AppleFactory.LoadItems(...))` and `Convert(OrangeFactory.LoadItems(...))`, then call `Task.WhenAll` with the two results. – Jon Skeet Jun 06 '16 at 20:10
  • This is good - and thanks for pushing back and making me think a bit harder :) – Geoff Jun 06 '16 at 20:26