我有以下代码,在类型之间转换项目R
并L
使用异步方法:
class MyClass<R,L> {
public async Task<bool> MyMethodAsync(List<R> remoteItems) {
...
List<L> mappedItems = new List<L>();
foreach (var remoteItem in remoteItems )
{
mappedItems.Add(await MapToLocalObject(remoteItem));
}
//Do stuff with mapped items
...
}
private async Task<L> MapToLocalObject(R remoteObject);
}
Run Code Online (Sandbox Code Playgroud)
这是否可以使用IEnumerable.Select调用(或类似)来减少代码行?我试过这个:
class MyClass<R,L> {
public async Task<bool> MyMethodAsync(List<R> remoteItems) {
...
List<L> mappedItems = remoteItems.Select<R, L>(async r => await MapToLocalObject(r)).ToList<L>();
//Do stuff with mapped items
...
}
}
Run Code Online (Sandbox Code Playgroud)
但我得到错误:
"无法将异步lambda表达式转换为委托类型
'System.Func<R,int,L>'
.异步lambda表达式可能会返回void
,Task
或者Task<T>
,没有一个可以转换为'System.Func<R,int,L>'
."
我相信我错过了关于async/await关键字的一些内容,但我无法弄清楚是什么.有没有人知道如何修改我的代码以使其有效?
Ste*_*ary 68
您可以通过考虑游戏中的类型来解决这个问题.例如,MapToLocalObject
- 当被视为异步函数时 - 映射R
到L
.但是如果你将它视为同步函数,它会映射R
到Task<L>
.
Task
是一个"未来",所以Task<L>
可以作为一种类型被认为是会产生一个L
在将来某一时刻.
因此,您可以轻松地从序列转换R
为以下序列Task<L>
:
IEnumerable<Task<L>> mappingTasks = remoteItems.Select(remoteItem => MapToLocalObject(remoteItem));
Run Code Online (Sandbox Code Playgroud)
请注意,这与您的原始代码之间存在重要的语义差异.原始代码在继续下一个对象之前等待映射每个对象; 此代码将同时启动所有映射.
您的结果是一系列任务 - 一系列未来L
结果.要处理任务序列,有一些常见的操作.Task.WhenAll
并且Task.WhenAny
是最常见要求的内置操作.如果要等到所有映射都完成,您可以执行以下操作:
L[] mappedItems = await Task.WhenAll(mappingTasks);
Run Code Online (Sandbox Code Playgroud)
如果您希望在完成后处理每个项目,可以OrderByCompletion
从我的AsyncEx库中使用:
Task<L>[] orderedMappingTasks = mappingTasks.OrderByCompletion();
foreach (var task in orderedMappingTasks)
{
var mappedItem = await task;
...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
18417 次 |
最近记录: |