Проблема с конвертацией и выводом результата. Вернуть результат Task>
У меня есть два связанных метода
public async Task<IEnumerable<BaseNewsContentItem>> GetContentItemRMMultipleAsync(IEnumerable<int> itemIds, UserKey user, bool needGetInfoByChat = true)
{
var items = await _feedDataService.GetItemsWithDependenciesAsync(itemIds, user);
if (items == null || !items.Any())
return null;
var tasks = new List<Task<BaseNewsContentItem>>();
foreach(var item in items)
{
tasks.Add(new Task(async () => await ToContentItemAsync(item, user?.ToUserIdVM(), needGetInfoByChat))); // Выдает ошибку cannot convert from Task to Task<BaseNewsContentItem>
}
return Task.WhenAll(tasks);// tasks имеет тип List<Task<BaseNewsContentItem>>, а нужно чтобы в результате метода выводилось Task<List<BaseNewsContentItem>>
}
и
private async Task<BaseNewsContentItem> ToContentItemAsync(BaseItem item, UserIdVM user, bool needGetInfoByChat = true)
{
if (item == null)
return null;
if (item.CommunityId.HasValue)
return await GetContentItem(item, user, needGetInfoByChat); //Возвращает Task<BaseNewsContentItem>
if (item.RegionGuid.HasValue)
return await GetContentItemByRegionGuid(item, user, needGetInfoByChat); //Возвращает Task<BaseNewsContentItem>
return await GetContentItemFromChats(item, user, needGetInfoByChat); //Возвращает Task<BaseNewsContentItem>
}
Как правильно исправить данные ошибки, чтобы получить нужную коллекцию?
Ответы (2 шт):
Здесь перемудрили
public async Task<BaseNewsContentItem[]> GetContentItemRMMultipleAsync(IEnumerable<int> itemIds, UserKey user, bool needGetInfoByChat = true)
{
var items = await _feedDataService.GetItemsWithDependenciesAsync(itemIds, user);
if (items == null || !items.Any())
return null;
var tasks = new List<Task<BaseNewsContentItem>>();
foreach(var item in items)
{
tasks.Add(ToContentItemAsync(item, user?.ToUserIdVM(), needGetInfoByChat));
}
return await Task.WhenAll(tasks);
}
Принимать IEnumerable есть смысл, для универсальности, а вот возвращать - нет, поэтому я верну массив. И вообще там где массивы, лучше работайте с массивами, не упаковывайтесь в IEnumerable, компилятор наградит вас за это более оптимизированным кодом.
А здесь можно убить машину состояний
private Task<BaseNewsContentItem> ToContentItemAsync(BaseItem item, UserIdVM user, bool needGetInfoByChat = true)
{
if (item == null)
return Task.FromResult<BaseNewsContentItem>(null);
if (item.CommunityId.HasValue)
return GetContentItem(item, user, needGetInfoByChat);
if (item.RegionGuid.HasValue)
return GetContentItemByRegionGuid(item, user, needGetInfoByChat);
return GetContentItemFromChats(item, user, needGetInfoByChat);
}
Можно кстати переписать вот так
private Task<BaseNewsContentItem> ToContentItemAsync(BaseItem item, UserIdVM user, bool needGetInfoByChat = true)
=> item switch
{
null => Task.FromResult<BaseNewsContentItem>(null),
_ when item.CommunityId.HasValue => GetContentItem(item, user, needGetInfoByChat),
_ when item.RegionGuid.HasValue => GetContentItemByRegionGuid(item, user, needGetInfoByChat),
_ => GetContentItemFromChats(item, user, needGetInfoByChat)
};
Но кому как больше нравится.
// Выдает ошибку cannot convert from Task to Task
В таком случае, удобнее объявить переменную tasks как new List<BaseNewsContentItem>. Но такое решение подходит тогда и только тогда, когда не надо запускать все задачи параллельно. В противном случае, смотреть ответ aepot.
public async Task<IEnumerable<BaseNewsContentItem>> GetContentItemRMMultipleAsync(IEnumerable<int> itemIds, UserKey user, bool needGetInfoByChat = true) {
var items = await _feedDataService.GetItemsWithDependenciesAsync(itemIds, user);
if(items == null || !items.Any())
return null;
var tasks = new List<BaseNewsContentItem>();
foreach(var item in items) {
tasks.Add(await ToContentItemAsync(item, user?.ToUserIdVM(), needGetInfoByChat));
}
return tasks;
}
К тому же, если вам доступен C# 8, то для вашей задачи как нельзя подходит IAsyncEnumerable:
public async IAsyncEnumerable<BaseNewsContentItem> GetContentItemRMMultipleAsync(IEnumerable<int> itemIds, UserKey user, bool needGetInfoByChat = true) {
var items = await _feedDataService.GetItemsWithDependenciesAsync(itemIds, user);
if(items != null) {
foreach(var item in items) {
yield return await ToContentItemAsync(item, user?.ToUserIdVM(), needGetInfoByChat);
}
}
}
public async Task Do() {
var items = GetContentItemRMMultipleAsync(...);
await foreach (var item in items) {
DoSomething(item);
}
}