代码之家  ›  专栏  ›  技术社区  ›  Andrew

如何从Task<List<Derivated>>转换为Task<List<Base>>[重复]

  •  -1
  • Andrew  · 技术社区  · 8 年前

    正如标题所述,我很好奇是否可以从 Task<List<Derived>> Task<List<BaseType>> ?

    我有几个方法可以返回 任务(<);列表(<);派生(>)&燃气轮机; ,并且可以有多个类型派生类。我想将所有任务存储在任务列表中: List<Task<List<BaseType>>> 待以后执行。

    如果我的任务不是包装列表,这将非常简单: link


    编辑1

    以下是我遇到的问题,我在列表中存储任务时遇到了问题:

    // This throws an error (cannot convert derived list to base list)
    var tasks = new List<Task<List<BaseType>>>
    {
        asyncThing1(), // returns Task<List<Derived1>>
        asyncThing2(), // returns Task<List<Derived2>>
        // ... n number more
    };
    
    // Need the list of tasks before I can execute
    List<BaseType>[] results = await Task.WhenAll(tasks);
    

    编辑2

    以上,已更改 List<Base>[] List<BaseType>[]

    2 回复  |  直到 8 年前
        1
  •  4
  •   Eric Lippert    8 年前

    正如标题所述,我很好奇是否可以从 Task<List<Derived>> Task<List<Base>> ?

    不。假设它是合法的,看看出了什么问题:

    Task<List<Giraffe>> t1 = GetGiraffesAsync();
    Task<List<Animal>> t2 = t1; // Suppose this were legal
    (await t2).Add(new Fish());
    

    现在我们在长颈鹿列表中有一条鱼。

    这三条线中必须有一条是非法的。显然这不是第一次,因为 GetGiraffesAsync 退货 Task<List<Giraffe>> .显然,这不可能是最后一次,因为 await t2 生成 List<Animal> 鱼是一种动物。因此,中间线一定是非法的。

    现在,您可以这样做:

    async Task<List<Animal>> ConvertAsync(Task<List<Giraffe>> t) => 
      (await t).Select(g => (Animal)g).ToList();
    

    async Task<List<Animal>> ConvertASync(Task<List<Giraffe>> t) => 
      (await t).Cast<Animal>().ToList();
    

    async Task<List<Animal>> ConvertAsync(Task<List<Giraffe>> t) => 
      (await t).OfType<Animal>().ToList();
    

    如果你想让它通用,你可以这样做

    async Task<<List>Animal> ConvertAsync<T>(Task<List<T>> t) where T : Animal =>
      (await t).OfType<Animal>().ToList();
    

    现在它可以与长颈鹿、鱼和老虎等动物合作。

    也就是说,您可以异步等待原始任务完成,完成后,您可以从长颈鹿列表中创建新的动物列表。这是完全合法的。你现在有 列表,一只长颈鹿和一只动物。

    或者,您可以这样做:

    async Task<IEnumerable<Animal>> ConvertAsync(Task<List<Giraffe>> t) => 
      await t;
    

    自从 List<Giraffe> 可转换为 IEnumerable<Animal>

    我倾向于将其作为一种扩展方法来编写。

    static class Extensions {
      public static Task<List<Animal>> ConvertAsync<T>(
        this Task<List<T>> t) where T : Animal {
          return (await t).OfType<Animal>().ToList();
      } 
    }
    

    现在您的程序片段是:

    var tasks = new List<Task<List<Animal>>>
    {
      GetGiraffesAsync().ConvertAsync(),
      GetTigersAsync().ConvertAsync()
    };
    
        2
  •  2
  •   Rand Random    8 年前

    作为一个小小的补充,您发布的链接只是缺少列表部分,以使其适用于您的场景。

    因此,这是在另一个主题中提出的: Cannot convert type 'Task<Derived>' to 'Task<Interface>'

    async Task<TBase> GeneralizeTask<TBase, TDerived>(Task<TDerived> task) 
        where TDerived : TBase 
    {
        return (TBase) await task;
    }
    

    您要搜索的是:

    async Task<List<TBase>> GeneralizeTask<TBase, TDerived>(Task<List<TDerived>> task) 
        where TDerived : TBase 
    {
        return (await task).Cast<TBase>().ToList();
    }
    

    你可以这样称呼它:

    var tasks = new List<Task<List<Animal>>>
    {
      GetGiraffesAsync().GeneralizeTask<Animal, Giraffe>(),
      GetTigersAsync().GeneralizeTask<Animal, Tiger>()
    };