为何无需async/await无法返回Task<IEnumerable<T>>?如何解决?
问题解答:Task<Descriptor[]> 无法直接转为 Task<IEnumerable> 的原因及无async/await解决方案
为什么直接return会报错?
- C# 里的
Task<T>是不变泛型类型,泛型参数不支持协变。也就是说,哪怕Descriptor[]本身实现了IEnumerable<Descriptor>,Task<Descriptor[]>也不能直接隐式转换成Task<IEnumerable<Descriptor>>——协变只适用于标记了out关键字的泛型接口/委托(比如IEnumerable<out T>),而Task<T>并不满足这个条件。 - 用
async/await时,await allDescriptors会先获取到Descriptor[]实例,而数组天然实现了IEnumerable<Descriptor>,所以这个实例可以直接隐式转换为方法返回值要求的IEnumerable<Descriptor>,再由async方法自动把它包装成Task<IEnumerable<Descriptor>>返回,自然不会报错。
不用async/await怎么返回预期类型?
可以通过ContinueWith方法延续原任务,把Descriptor[]结果转换为IEnumerable<Descriptor>类型,从而得到符合返回要求的Task<IEnumerable<Descriptor>>:
public Task<IEnumerable<Descriptor>> GetAllDescriptors() { var allDescriptorsTask = Task.WhenAll(GetMovieDescriptorAsync(), GetSongDescriptorAsync()); // 延续任务,将结果数组转换为IEnumerable<Descriptor> return allDescriptorsTask.ContinueWith(task => (IEnumerable<Descriptor>)task.Result); }
或者用语义更清晰的AsEnumerable()方法实现转换:
public Task<IEnumerable<Descriptor>> GetAllDescriptors() { var allDescriptorsTask = Task.WhenAll(GetMovieDescriptorAsync(), GetSongDescriptorAsync()); return allDescriptorsTask.ContinueWith(task => task.Result.AsEnumerable()); }
注:ContinueWith默认沿用原任务的调度上下文,若需指定调度器,可添加第二个参数(比如TaskScheduler.Default),多数场景下默认行为即可满足需求。
内容的提问来源于stack exchange,提问作者so_as
相关产品推荐
相关产品推荐

