9

I have the following program:

async Task Main()
{
    IList<int> myList = await TestAsync();
}

public Task<IList<int>> TestAsync()
{
    return Task.FromResult(new List<int>());
}

The compiler complains that it can't convert a Task<List> to a Task<IList> in the TestAsync method:

CS0029 Cannot implicitly convert type System.Threading.Tasks.Task<System.Collections.Generic.List<int>> to System.Threading.Tasks.Task<System.Collections.Generic.IList<int>>

Why can't it figure out that my method returns a Task of IList?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Kzryzstof
  • 7,688
  • 10
  • 61
  • 108

1 Answers1

15

Why can't it figure out that my method returns an Task of IList<int>?

Because it doesn't. In this call:

Task.FromResult(new List<int>());

... type inference makes that equivalent to:

Task.FromResult<List<int>>(new List<int>());

So your method is trying to return a Task<List<int>> - and that's not compatible with Task<IList<int>>.

To simplify the point about Task<>, let's use string and object instead, and take out type inference and async entirely. The following code does not compile, and indeed shouldn't:

Task<string> stringTask = Task.FromResult<string>("text");
Task<object> objectTask = stringTask; // Doesn't compile

Task<T> is invariant - there's no conversion from Task<T1> to Task<T2> just because there's a conversion from T1 to T2.

You don't need an explicit cast though - you can just use the implicit conversion earlier:

public Task<IList<int>> TestAsync()
{
    // It's important that this variable is explicitly typed as IList<int>
    IList<int> result = new List<int>();
    return Task.FromResult(result);
}

This uses the implicit conversion from List<int> to IList<int> for the result variable, and then it calls Task.FromResult<IList<int>> using type inference.

An alternative is to keep the method as it was before, except you specify the type argument for Task.FromResult:

public Task<IList<int>> TestAsync()
{
    return Task.FromResult<IList<int>>(new List<int>());
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194