异步Lambda表达式编译失败,寻求正确async/await使用方案
异步Select构建对象数组的正确实现方式
问题根源
你当前的代码中,Select(async s => ...)会返回IEnumerable<Task<ResourcesResponse.Resource>>,直接调用.ToArray()得到的是Task<ResourcesResponse.Resource>[],但ResourcesResponse.Resources属性要求的是ResourcesResponse.Resource[],类型不匹配导致编译失败。同时异步任务必须被等待才能拿到实际对象,不能用.Result阻塞线程。
解决方案
拆分异步任务处理流程:先生成所有子资源的异步任务集合,再用Task.WhenAll()批量等待所有任务完成,最后将结果转为目标类型数组。
修改后的完整代码
// 先生成所有子资源的异步任务集合 var resourceTasks = aux .OrderBy(k => k.Order) .ThenBy(k => k.TypeId) .Select(async s => new ResourcesResponse.Resource { Id = ((ulong)s.Id).ToString(), Charge = s.Charge, Cost = s.Cost, CurrencyCode = s.CurrencyCode, ForecastCharge = s.ForecastCharge, ForecastCost = s.ForecastCost, ForecastUsedUnits = s.ForecastUsedUnits, ParentId = ((ulong?)s.ParentId).ToString(), Order = await _resourcesRepository.GetResourceTypeOrder(s.TypeId), Rate = s.Rate, TypeId = s.TypeId, UsedUnits = s.UsedUnits, // 注意:Resource类定义中的Type属性未在原代码赋值,需补充逻辑(示例调用仓储方法) Type = await _resourcesRepository.GetResourceTypeName(s.TypeId) }); // 等待所有异步任务完成,得到Resource数组 var resources = await Task.WhenAll(resourceTasks); // 实例化ResourcesResponse var tmp = new ResourcesResponse { Cost = aux.Sum(s => s.Cost), Resources = resources, Id = ((ulong)entry.Id).ToString(), Name = entry.Name, Description = entry.Description, OriginalId = entry.OriginalId, ResourceTypeId = entry.ResourceTypeId, ResourceType = await _resourcesRepository.GetResourceTypeName(entry.ResourceTypeId), Order = await _resourcesRepository.GetResourceTypeOrder(entry.ResourceTypeId), State = entry.State, Zone = entry.Zone, Charge = aux.Sum(s => s.Charge), };
性能优化建议
如果子资源存在大量重复的TypeId,可以批量获取所有需要的Order值,减少异步调用次数:
// 批量去重获取所有需要的TypeId var distinctTypeIds = aux.Select(s => s.TypeId).Distinct(); // 批量发起异步请求并等待完成 var orderTaskMap = distinctTypeIds.ToDictionary(id => id, id => _resourcesRepository.GetResourceTypeOrder(id)); await Task.WhenAll(orderTaskMap.Values); // 构建Order映射表(任务已完成,使用.Result不会阻塞) var orderMap = orderTaskMap.ToDictionary(kv => kv.Key, kv => kv.Value.Result); // 同步构建子资源数组 var resources = aux .OrderBy(k => k.Order) .ThenBy(k => k.TypeId) .Select(s => new ResourcesResponse.Resource { Id = ((ulong)s.Id).ToString(), // ...其他属性赋值 Order = orderMap[s.TypeId], // ...其他属性 }) .ToArray();
内容的提问来源于stack exchange,提问作者Diego Perez
相关产品推荐
相关产品推荐

