如何转换Task <list <derived>&gt;到任务<list <base>&gt;

时间:2018-05-08 15:19:51

标签: c# generics asynchronous async-await

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

我有几个返回Task<List<Derived>>的方法,并且可以有多个类型的派生类。我想将所有任务存储在一个任务列表中: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 个答案:

答案 0 :(得分:4)

  

正如标题所述,我很好奇是否可以从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()
};

答案 1 :(得分:2)

正如一点注意事项,您发布的链接只是缺少List部分,以使其适用于您的场景。

所以这是在另一个主题中提出的: 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>()
};