如何从 Task<List<Derived>> 转换为 Task<List<Base>>

And*_*rew -1 c# generics asynchronous async-await

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

我有几个返回 的方法Task<List<Derived>>,并且可以有多种类型的派生类。我想将所有任务存储在任务列表中:List<Task<List<BaseType>>>稍后执行。

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


编辑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);
Run Code Online (Sandbox Code Playgroud)

编辑2

以上,List<Base>[]改为List<BaseType>[]

Eri*_*ert 5

正如标题所述,我很好奇是否可以从 转换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());
Run Code Online (Sandbox Code Playgroud)

现在我们在长颈鹿列表中添加了一条鱼。

这三行之一必须是非法的。显然它不可能是第一个,因为GetGiraffesAsyncreturns Task<List<Giraffe>>。显然它不可能是最后一个,因为await t2产生一个List<Animal>,而鱼是一种动物。因此,非法的必定是中线。

现在,你可以这样做:

async Task<List<Animal>> ConvertAsync(Task<List<Giraffe>> t) => 
  (await t).Select(g => (Animal)g).ToList();
Run Code Online (Sandbox Code Playgroud)

或者

async Task<List<Animal>> ConvertASync(Task<List<Giraffe>> t) => 
  (await t).Cast<Animal>().ToList();
Run Code Online (Sandbox Code Playgroud)

或者

async Task<List<Animal>> ConvertAsync(Task<List<Giraffe>> t) => 
  (await t).OfType<Animal>().ToList();
Run Code Online (Sandbox Code Playgroud)

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

async Task<<List>Animal> ConvertAsync<T>(Task<List<T>> t) where T : Animal =>
  (await t).OfType<Animal>().ToList();
Run Code Online (Sandbox Code Playgroud)

现在它适用于长颈鹿、鱼和老虎等。

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

或者,你可以这样做:

async Task<IEnumerable<Animal>> ConvertAsync(Task<List<Giraffe>> t) => 
  await t;
Run Code Online (Sandbox Code Playgroud)

因为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();
  } 
}
Run Code Online (Sandbox Code Playgroud)

现在你的程序片段是:

var tasks = new List<Task<List<Animal>>>
{
  GetGiraffesAsync().ConvertAsync(),
  GetTigersAsync().ConvertAsync()
};
Run Code Online (Sandbox Code Playgroud)

  • 扩展方法正是我正在寻找的。感谢您详细解释的答案! (2认同)