您当前的实现不需要任何异步代码。
我想这只是一个简化的例子,所以我将它们视为异步方法。
static async Task Main(string[] args)
{
var odds = await GetOddNumbers();
var evens = await GetEvenNumbers();
var numbers = (odds).Zip(evens)
.SelectMany(tuple => new [] { tuple.First, tuple.Second });
Console.ReadLine();
}
- 我们检索这两个集合。
- 我们将
odds 中的一个元素组合(Zip) 到evens 中的另一个元素。因此,我们最终会得到以下结构(元组数组):
[
(1,2),
(3,4),
(5,6),
(7,8),
(9,10),
]
- 为了展平它,我们需要调用
SelectMany。您可以通过First 属性访问左侧项目,通过Second 属性访问右侧项目。
3.1) 如果你只调用Select 而不是SelectMany 那么你最终会得到一个数组数组。
[
[1,2],
[3,4],
[5,6],
[7,8],
[9,10],
]
3.2) 但是使用SelectMany,我们将数组数组展平为一个简单数组。
[
1,2,3,4,5,6,7,8,9,10
]
更新:OP 添加了一个新要求(作为注释),即应逐个异步检索数据。
为了满足这一点,我们需要使用IAsyncEnumerable<T>。这使我们能够在数据可用时一次提供一个数据。
提供方
因此,我们必须返回IAsyncEnumerable<int>,而不是返回Task<int[]>。 GetOddNumbers 和 GetEvenNumbers 可以这样重写:
public static async IAsyncEnumerable<int> GetOddNumbers()
{
var odds = new int[] { 1, 3, 5, 7, 9 };
foreach (var odd in odds)
{
await Task.Delay(1000); //Whatever async method call
yield return odd;
}
}
public static async IAsyncEnumerable<int> GetEvenNumbers()
{
var evens = new int[] { 2, 4, 6, 8, 10 };
foreach (var even in evens)
{
await Task.Delay(1000); //Whatever async method call
yield return even;
}
}
消费者方面
我们可以利用 C# 8 新的 await foreach 关键字。IAsyncEnumerable 没有内置的 Zip 函数,因此我们需要使用自定义函数,例如:async-enumerable-dotnet
有了这些,Main 方法将如下所示:
static async Task Main(string[] args)
{
var toBeIterated = async_enumerable_dotnet.AsyncEnumerable.Zip(z => z, GetOddNumbers(), GetEvenNumbers());
await foreach (int[] oddEvenPair in toBeIterated)
{
Console.WriteLine(oddEvenPair[0]);
Console.WriteLine(oddEvenPair[1]);
}
Console.WriteLine("Finished");
Console.ReadLine();
}
它将一次打印出一对数据,然后在下一对数据之间等待一秒。
{1 sec wait}
1
2
{1 sec wait}
3
4
{1 sec wait}
5
6
{1 sec wait}
7
8
{1 sec wait}
9
10
Finished