如何添加异步“;等待”;到addrangeselect语句
本文关键字:等待 语句 addrangeselect 异步 何添加 添加 | 更新日期: 2023-09-27 18:21:35
我有一个这样的函数:
public async Task<SomeViewModel> SampleFunction()
{
var data = service.GetData();
var myList = new List<SomeViewModel>();
myList.AddRange(data.select(x => new SomeViewModel
{
Id = x.Id,
DateCreated = x.DateCreated,
Data = await service.GetSomeDataById(x.Id)
}
return myList;
}
我的await
不起作用,因为它只能在用async
修饰符标记的方法或lambda中使用。带此功能的async
应该放在哪里?
只能在async
方法/委托中使用await
。在这种情况下,必须将该lambda表达式标记为async
。
但是等等,还有更多。。。
Select
来自前async
时代,因此它不处理async
lambdas(在您的情况下,它将返回IEnumerable<Task<SomeViewModel>>
,而不是您实际需要的IEnumerable<SomeViewModel>
)。
但是,您可以自己添加该功能(最好是作为一种扩展方法),但您需要考虑是希望在继续下一个项目之前await
每个项目(按顺序),还是希望在最后await
所有项目(同时)。
顺序async
static async Task<TResult[]> SelectAsync<TItem, TResult>(this IEnumerable<TItem> enumerable, Func<TItem, Task<TResult>> selector)
{
var results = new List<TResult>();
foreach (var item in enumerable)
{
results.Add(await selector(item));
}
return results.ToArray();
}
并发async
static Task<TResult[]> SelectAsync<TItem, TResult>(this IEnumerable<TItem> enumerable, Func<TItem, Task<TResult>> selector)
{
return Task.WhenAll(enumerable.Select(selector));
}
用法
public Task<SomeViewModel[]> SampleFunction()
{
return service.GetData().SelectAsync(async x => new SomeViewModel
{
Id = x.Id,
DateCreated = x.DateCreated,
Data = await service.GetSomeDataById(x.Id)
}
}
您在lambda内部使用await
,该lambda将由编译器转换为其自己的单独命名方法。要使用await
,它本身必须是async
,而不仅仅是在async
方法中定义的。当您生成lambda async
时,您现在有了一系列任务,您希望将这些任务异步转换为它们的结果序列。Task.WhenAll
正是这样做的,所以我们可以将我们的新查询传递给WhenAll
,以获得表示我们的结果的任务,这正是该方法想要返回的:
public Task<SomeViewModel[]> SampleFunction()
{
return Task.WhenAll(service.GetData().Select(
async x => new SomeViewModel
{
Id = x.Id,
DateCreated = x.DateCreated,
Data = await service.GetSomeDataById(x.Id)
}));
}
尽管对您的用例来说可能太重了,但使用TPL数据流将使您能够更好地控制异步处理。
public async Task<List<SomeViewModel>> SampleFunction()
{
var data = service.GetData();
var transformBlock = new TransformBlock<X, SomeViewModel>(
async x => new SomeViewModel
{
Id = x.Id,
DateCreated = x.DateCreated,
Data = await service.GetSomeDataById(x.Id)
},
new ExecutionDataflowBlockOptions
{
// Let 8 "service.GetSomeDataById" calls run at once.
MaxDegreeOfParallelism = 8
});
var result = new List<SomeViewModel>();
var actionBlock = new ActionBlock<SomeViewModel>(
vm => result.Add(vm));
transformBlock.LinkTo(actionBlock,
new DataflowLinkOptions { PropagateCompletion = true });
foreach (var x in data)
{
transformBlock.Post(x);
}
transformBlock.Complete();
await actionBlock.Completion;
return result;
}
如果service.GetData()
返回IObservable<X>
,而此方法返回IObservable<SomeViewModel>
,则这可能不会太冗长。