[英]Why can't I return a Task<IEnumerable<out T>> without making my method async and using await
Currently I have a method with the signature public Task<IEnumerable<Descriptor>> GetAllDescriptors()
where Descriptor
is a public class I created.目前我有一个签名为
public Task<IEnumerable<Descriptor>> GetAllDescriptors()
的方法,其中Descriptor
是我创建的 public class。 I then have various tasks that I call within this method like so:然后我在这个方法中调用了各种任务,如下所示:
var allDescriptors = Task.WhenAll(GetMovieDescriptorsAsync, GetSongDescriptorsAsync);
Since GetMovieDescriptorsAsync
& GetSongDescriptorsAsync
both return Task<Descriptor>
I know that the variable type of allDescriptors
is Task<Descriptor[]>
which is great.由于
GetMovieDescriptorsAsync
和GetSongDescriptorsAsync
都返回Task<Descriptor>
我知道allDescriptors
的变量类型是Task<Descriptor[]>
这很好。 However if I try return allDescriptors
I get the error:但是,如果我尝试
return allDescriptors
,则会收到错误消息:
Cannot implicitly convert type 'System.Threading.Tasks.Task<Descriptor[]>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<Descriptor>>'
However, if I change the method signature to public async Task<IEnumerable<Descriptor>> GetAllDescriptors()
and then I try return await allDescriptors
it works and I get the desired <IEnumerable<CompletionInfo>
in the calling function:但是,如果我将方法签名更改为
public async Task<IEnumerable<Descriptor>> GetAllDescriptors()
然后我尝试return await allDescriptors
它工作并且我在调用 function 中获得所需的<IEnumerable<CompletionInfo>
:
var descriptors = await GetAllDescriptors();
Why is that and how can I return the expected IEnumerable<Descriptor>
without having to use async and await?为什么会这样,我怎样才能返回预期的
IEnumerable<Descriptor>
而不必使用异步和等待?
Task.WhenAll<T>
returns a Task<T[]>
, so in your case Task.WhenAll<T>
返回一个Task<T[]>
,所以在你的情况下
Task<IEnumerable<Decsriptor>[]> allDescriptors = Task.WhenAll(GetMovieDescriptorsAsync, GetSongDescriptorsAsync);
allDescriptors
is a Task<IEnumerable<Decsriptor>[]>
, that is a Task wrapping an array of Enumerables of Descriptor. allDescriptors
是一个Task<IEnumerable<Decsriptor>[]>
,它是一个包装了描述符枚举数组的任务。
First order of business would be getting the task result:首要任务是获取任务结果:
IEnumerable<Descriptor>[] taskResults = allDescriptors.Result;
Then merging each IEnumerable<Descriptor>
in the array taskResults
into a flat list:然后将数组
taskResults
中的每个IEnumerable<Descriptor>
合并到一个平面列表中:
IEnumerable<Descriptor> descriptors = taskResults.SelectMany(value => value);
The problem (and solution) you are describing is covariance
.您描述的问题(和解决方案)是
covariance
。 IEnumerable<out T>
is a covariant interface, which means you can assign IEnumerable<string>
into IEnumerable<object>
. IEnumerable<out T>
是协变接口,这意味着您可以将IEnumerable<string>
分配给 IEnumerable IEnumerable<object>
。
However, Task<TResult>
IS NOT covariant.但是,
Task<TResult>
不是协变的。 That means you can't return a more specific object in place of a generic definition (if you've Task<object>
, you can't return Task<string>
).这意味着您不能返回更具体的 object 来代替通用定义(如果您有
Task<object>
,则不能返回Task<string>
)。
Now, adding async
and await
makes the compiler treat this a bit differently.现在,添加
async
和await
会使编译器对此有所不同。 Simplifying, async
cancels out the Task
declaration, so it returns the TResult
.简化,
async
取消了Task
声明,因此它返回TResult
。 And if you have a method object Foo()
, you can use return ""
inside this method.如果你有一个方法
object Foo()
,你可以在这个方法中使用return ""
。 Because the return type of a method is always covariant.因为方法的返回类型总是协变的。
To summarize, async Task<TResult>
is similar of TResult
, so you can return more specific objects this way.总而言之,
async Task<TResult>
与TResult
类似,因此您可以通过这种方式返回更具体的对象。 However, Task<TResult>
is a non-covariant type, so you have to return exactly the type specified.但是,
Task<TResult>
是一种非协变类型,因此您必须准确返回指定的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.