Проблема с конвертацией и выводом результата. Вернуть результат 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 шт):

Автор решения: aepot

Здесь перемудрили

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)
    };

Но кому как больше нравится.

→ Ссылка
Автор решения: Uranus

// Выдает ошибку 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);
    }
}
→ Ссылка