Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Task.FromResult require explicit cast? [duplicate]

Tags:

c#

I have the follow 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 an Task of IList?

like image 485
Kzrystof Avatar asked Jul 30 '18 16:07

Kzrystof


People also ask

Is it good to use task FromResult?

The FromResult method returns a finished Task<TResult> object that holds the provided value as its Result property. This method is useful when you perform an asynchronous operation that returns a Task<TResult> object, and the result of that Task<TResult> object is already computed.

What is task CompletedTask?

Gets a task that has already completed successfully. public: static property System::Threading::Tasks::Task ^ CompletedTask { System::Threading::Tasks::Task ^ get(); };

What should I return from Task C#?

The recommended return type of an asynchronous method in C# is Task. You should return Task<T> if you would like to write an asynchronous method that returns a value. If you would like to write an event handler, you can return void instead. Until C# 7.0 an asynchronous method could return Task, Task<T>, or void.

How do I return a Boolean task?

To return Boolean from Task Synchronously, we can use Task. FromResult<TResult>(TResult) Method. This method creates a Task result that's completed successfully with the specified result. The calling method uses an await operator to suspend the caller's completion till called async method has finished successfully.


1 Answers

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>());
}
like image 56
Jon Skeet Avatar answered Oct 18 '22 19:10

Jon Skeet