Ale*_*bin 2 .net c# linq async-await
假设我有以下示例代码:
private static async Task Main(string[] args)
{
var result = Enumerable.Range(0, 3).Select(x => TestMethod(x)).ToArray();
Console.ReadKey();
}
private static int TestMethod(int param)
{
Console.WriteLine($"{param} before");
Thread.Sleep(50);
Console.WriteLine($"{param} after");
return param;
}
Run Code Online (Sandbox Code Playgroud)
TestMethod 将运行完成 3 次,因此我将看到 3 对before和after:
0 before
0 after
1 before
1 after
2 before
2 after
Run Code Online (Sandbox Code Playgroud)
现在,我需要使 TestMethod 异步:
private static async Task<int> TestMethod(int param)
{
Console.WriteLine($"{param} before");
await Task.Delay(50);
Console.WriteLine($"{param} after");
return param;
}
Run Code Online (Sandbox Code Playgroud)
如何为此异步方法编写类似的 Select 表达式?如果我只使用 async lambda Enumerable.Range(0, 3).Select(async x => await TestMethod(x)).ToArray();,那将不起作用,因为它不会等待完成,因此before将首先调用部分:
0 before
1 before
2 before
2 after
0 after
1 after
Run Code Online (Sandbox Code Playgroud)
请注意,我不想并行运行所有 3 个调用 - 我需要它们一个接一个地执行,仅当前一个调用完全完成并返回值时才开始下一个调用。
我经常遇到这个要求,但我不知道 C# 7.2 有任何内置解决方案可以解决这个问题。我通常只是回退到使用awaita 中的每个异步操作foreach,但您可以使用扩展方法:
public static class EnumerableExtensions
{
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, Task<TResult>> asyncSelector)
{
var results = new List<TResult>();
foreach (var item in source)
results.Add(await asyncSelector(item));
return results;
}
}
Run Code Online (Sandbox Code Playgroud)
然后您可以await致电SelectAsync:
static async Task Main(string[] args)
{
var result = (await Enumerable.Range(0, 3).SelectAsync(x => TestMethod(x))).ToArray();
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
这种方法的缺点是急于求成SelectAsync,而不是懒惰。C# 8 承诺引入异步流,这将允许它再次变得懒惰。
| 归档时间: |
|
| 查看次数: |
3667 次 |
| 最近记录: |