Amir M
Amir M

Reputation: 550

Enumerable.SelectMany throws Error CS0411 - cannot be inferred from the usage

I'm using c#, .net 6.0

I'm trying to convert IEnumerable method and ot's caller method to work asynchronously.

I have a code that looks something like that:

    public IEnumerable<MyUser> getUsers()
{
    return AccountById
        .Keys
        .SelectMany(accountId => {
            try
            {
                return getUsersFor(accountId)
                    .Select(x => new MyUser(x,
                        SetAccountUniqueName(AccountById[accountId].Name,
                            AccountById[accountId].Id)));
            }
            catch (Exception ex)
            {
                _log.Error(ex);
                return Enumerable.Empty<MyUser>();
            }
        });
}

public IEnumerable<User> getUsersFor(string accountId)
{
    ListUsersResponse usersResponse;
    string marker = null;
    do
    {
        using (var myClient = new ServiceClient(accountId))
        {
            usersResponse =
                myClient.ListUsersAsync(
                        new ListUsersRequest { Marker = marker, MaxItems = MAX_ITEMS })
                    .Result;
            foreach (var user in usersResponse.Users)
            {
                yield return user;
            }
        }

        marker = usersResponse.Marker;
    } while (usersResponse.IsTruncated);
}

I converted getUsers() and getUsersFor() to work asynchronously.

I tried this code:

    public async Task<List<MyUser>> GetUsersAsync()
    {
        return await AccountById
            .Keys
            .SelectMany(async accountId =>
            {
                try
                {
                    await foreach (var user in GetUsersForAsync(accountId))
                    {
                        var u = new MyUser(user,
                            SetAccountUniqueName(AccountById[accountId].Name,
                                AccountById[accountId].Id));
                        return u;
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"Failed to get account {accountId} users list.");
                    return Enumerable.Empty<MyUser>();
                }
            });
    }

    public async IAsyncEnumerable<User> GetUsersForAsync(string accountId)
    {
        ListUsersResponse usersResponse;
        string marker = null;
        do
        {
            using (var myClient = new ServiceClient(accountId))
            {
                usersResponse =
                    await myClient.ListUsersAsync(
                            new ListUsersRequest { Marker = marker, MaxItems = MAX_ITEMS });
                foreach (var user in usersResponse.Users)
                {
                    yield return user;
                }
            }

            marker = usersResponse.Marker;
        } while (usersResponse.IsTruncated);
    }

But I get this error:

The type arguments for method 'Enumerable.SelectMany<TSource, TResult>(IEnumerable, Func<TSource, IEnumerable>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Upvotes: 0

Views: 241

Answers (1)

Svyatoslav Danyliv
Svyatoslav Danyliv

Reputation: 27528

You should not use LINQ for asynchronous operations. SelectMany of asynchronous call returns Task which is wrong way if you do not await them.

Simple foreach will work in your case, don't complicate things.

public async Task<List<MyUser>> GetUsersAsync()
{
    var result = new List<MyUser>();
    foreach (var accountId in AccountById.Keys)
    {
        try
        {
            await foreach (var user in GetUsersForAsync(accountId))
            {
                var u = new MyUser(user,
                    SetAccountUniqueName(AccountById[accountId].Name,
                        AccountById[accountId].Id));
                result.Add(u);
            }
        }
        catch (Exception ex)
        {
            _logger.Error(ex, $"Failed to get account {accountId} users list.");
        }    
    }

    return result;
}

Upvotes: 0

Related Questions