Reputation: 2208
I have this code:
static List<string> lst = new List<string>();
public static Task<IEnumerable<String>> GetStrings() {
IEnumerable<String> x = lst;
// This line below compiles just fine.
// return Task.Run(() => x);
// This line gives a compiler error:
// Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List<string>>' to
// 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<string>>'
return Task.Run(() => lst);
}
Why does this line compile just fine: return Task.Run(() => x);
while return Task.Run(() => lst);
gives the compiler error:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable>'
I would think that since List<string>
is an IEnumerable<string>
, I should not have to explicitly set x
. I mean, the compiler knows lst
is an IEnumerable<string>
.
I think I must be missing something fundamental here.
Upvotes: 1
Views: 166
Reputation: 172448
Because C# first tries to determine the type of your expression Task.Run(() => lst)
and then checks whether it is a suitable return type for your method.
lst
is a List<string>
.() => lst
is a lambda with a return value of List<string>
.Task.Run<TResult>(Func<TResult>)
called with () => lst
infers List<string>
as its type parameter TResult
.Task.Run(() => lst)
is of type Task<List<string>>
.You then try to use a value of type Task<List<string>>
as the return value of a method returning a Task<IEnumerable<string>>
. Task<TResult>
is not covariant, hence, you get a compile-time error.
(As an aside: Having a covariant ITask<out TResult>
interface would fix this, but the .NET development team decided against it.)
Yes, the compiler could check how you are using the expression created in step 4 and try different interfaces of lst
to make it fit, but that's a feature that C# (currently) does not have (and which, in my purely personal opinion, is probably not worth implementing and maintaining due to its low cost-benefit ratio).
To solve this, you can either provide a different type in step 2, by explicitly casting the return type:
return Task.Run(() => (IEnumerable<string>)lst);
or by explicitly declaring the type of the lambda expression:
return Task.Run(new Func<IEnumerable<string>>(() => lst));
or you could override the automatic inference in step 3 with an explicit type argument:
return Task.Run<IEnumerable<string>>(() => lst);
Upvotes: 5
Reputation: 1287
The problem is that you are using different data types here (List<T>
vs. IEnumerable<T>
). You can fix the issue with using type casting like:
Task.Run(() => (IEnumerable<string>)lst);
Upvotes: 1